lanos / laravel-property-data
A Laravel package for handling UK property data
Requires
- php: ^8.1
- guzzlehttp/guzzle: ^7.0
- illuminate/contracts: ^10.0|^11.0
- illuminate/support: ^10.0|^11.0
Requires (Dev)
- laravel/pint: ^1.0
- mockery/mockery: ^1.6
- nunomaduro/collision: ^7.0|^8.0
- orchestra/testbench: ^8.0|^9.0
- pestphp/pest: ^2.0
- pestphp/pest-plugin-arch: ^2.0
- pestphp/pest-plugin-laravel: ^2.0
- phpstan/extension-installer: ^1.1
- phpstan/phpstan-deprecation-rules: ^1.0
- phpstan/phpstan-phpunit: ^1.0
README
A comprehensive Laravel package for integrating with the PropertyData UK property data API. This package provides a clean, intuitive interface for accessing UK property market data, valuations, planning information, and area analytics.
📋 Table of Contents
- About PropertyData API
- Features
- Requirements
- Installation
- Configuration
- Quick Start
- Available Methods
- Usage Examples
- Error Handling
- Testing
- Changelog
- Contributing
- Security
- Credits
- License
- Disclaimer
About PropertyData API
This package integrates with the PropertyData API - a comprehensive UK property data service.
⚠️ Important: You need an API key to use this package.
👉 Get your API key at: https://propertydata.co.uk
📚 API Documentation: https://propertydata.co.uk/api/documentation
PropertyData provides access to:
- Property valuations and market analytics
- Planning applications and building regulations
- Area demographics and statistics
- Crime data and school information
- Development feasibility calculations
- And much more...
Features
✨ Key Features:
- 🏠 Comprehensive Property Data: Access sold prices, valuations, rental yields, and market trends
- 📍 Location Intelligence: Area demographics, crime statistics, school ratings, and amenities
- 🏗️ Development Tools: Development calculators, GDV estimates, build costs, and feasibility analysis
- 📋 Planning Data: Planning applications, conservation areas, green belt checks, and listed buildings
- 🔍 Property Search: UPRN lookups, address matching, and title searches
- 💰 Financial Calculators: Mortgage calculators, stamp duty, and rebuild cost estimates
- 🔄 Automatic Retry Logic: Built-in retry mechanism for transient failures
- ✅ Input Validation: Comprehensive validation for all API parameters
- 🎯 Type Safety: PHP 8.1+ enums for constrained values
- 📝 Full Laravel Integration: Service provider, facade, and configuration publishing
Requirements
- PHP 8.1 or higher
- Laravel 10.x or 11.x
- Composer
- PropertyData API key (get one at propertydata.co.uk)
Installation
Step 1: Install via Composer
composer require lanos/laravel-property-data
Step 2: Publish Configuration (Optional)
The package will auto-register its service provider through Laravel's package discovery. To publish the configuration file:
php artisan vendor:publish --tag=property-data-config
This will create a config/property-data.php
configuration file.
Step 3: Add API Key to Environment
Add your PropertyData API key to your .env
file:
PROPERTY_DATA_API_KEY=your-api-key-here
You can also configure optional settings:
# API Configuration PROPERTY_DATA_API_URL=https://api.propertydata.co.uk PROPERTY_DATA_API_TIMEOUT=30 # Logging PROPERTY_DATA_LOGGING_ENABLED=true PROPERTY_DATA_LOG_CHANNEL=stack # Retry Configuration PROPERTY_DATA_RETRY_ENABLED=true PROPERTY_DATA_RETRY_ATTEMPTS=3 PROPERTY_DATA_RETRY_DELAY=1000
Configuration
The configuration file (config/property-data.php
) contains:
return [ 'api' => [ 'base_url' => env('PROPERTY_DATA_API_URL', 'https://api.propertydata.co.uk'), 'key' => env('PROPERTY_DATA_API_KEY', ''), 'timeout' => env('PROPERTY_DATA_API_TIMEOUT', 30), 'retry' => [ 'enabled' => env('PROPERTY_DATA_RETRY_ENABLED', true), 'max_attempts' => env('PROPERTY_DATA_RETRY_ATTEMPTS', 3), 'delay' => env('PROPERTY_DATA_RETRY_DELAY', 1000), // milliseconds ], ], 'logging' => [ 'enabled' => env('PROPERTY_DATA_LOGGING_ENABLED', true), 'channel' => env('PROPERTY_DATA_LOG_CHANNEL', config('logging.default')), ], ];
Quick Start
Using the Facade
use PropertyData; // Get property valuation $valuation = PropertyData::valuationSale('SW1A 1AA', beds: 3, sqft: 1200); // Get area demographics $demographics = PropertyData::demographics(postcode: 'SW1A 1AA'); // Check planning applications $planning = PropertyData::planningApplications(postcode: 'SW1A 1AA');
Using Dependency Injection
use Lanos\LaravelPropertyData\LaravelPropertyData; class PropertyController extends Controller { public function __construct( private LaravelPropertyData $propertyData ) {} public function show(string $postcode) { $data = $this->propertyData->prices($postcode); return view('property.show', compact('data')); } }
Available Methods
📍 Address & UPRN Methods
// Match address to UPRN $uprns = PropertyData::addressMatchUprn('123 Example Street, London, SW1A 1AA'); // Lookup property by UPRN $property = PropertyData::uprn('123456789012'); // Lookup multiple UPRNs $properties = PropertyData::uprns(['123456789012', '123456789013']); // Get Land Registry title for UPRN $title = PropertyData::uprnTitle('123456789012');
💰 Market Data Methods
// Current asking prices $prices = PropertyData::prices('SW1A 1AA', page: 1, perPage: 20); // Prices per square foot $pricesPerSqf = PropertyData::pricesPerSqf('SW1A 1AA'); // Sold prices from Land Registry $soldPrices = PropertyData::soldPrices('SW1A 1AA'); // Rental market statistics $rents = PropertyData::rents('SW1A 1AA'); // HMO rent estimates $hmoRents = PropertyData::rentsHmo('SW1A 1AA'); // Yield calculations $yields = PropertyData::yields('SW1A 1AA'); // Price growth metrics $growth = PropertyData::growth('SW1A 1AA'); // Property demand analytics $demand = PropertyData::demand(postcode: 'SW1A 1AA');
🏠 Valuation Methods
// Instant sale valuation $valuation = PropertyData::valuationSale('SW1A 1AA', beds: 3, sqft: 1200); // Rent valuation $rentValuation = PropertyData::valuationRent('SW1A 1AA'); // HMO valuation $hmoValuation = PropertyData::valuationHmo('SW1A 1AA'); // Historical valuations $history = PropertyData::valuationHistorical('SW1A 1AA', page: 1);
🏗️ Development Methods
use Lanos\LaravelPropertyData\Enums\ProjectType; use Lanos\LaravelPropertyData\Enums\FinishQuality; // Development feasibility calculator $feasibility = PropertyData::developmentCalculator( postcode: 'SW1A 1AA', purchasePrice: 500000, sqftPreDevelopment: 1000, sqftPostDevelopment: 1500, projectType: ProjectType::REFURBISH, finishQuality: FinishQuality::PREMIUM, town: 'London' // optional ); // Gross Development Value estimate $gdv = PropertyData::developmentGdv( postcode: 'SW1A 1AA', town: 'London', flat0: 0, // Studio flats flat1: 2, // 1-bed flats flat2: 3, // 2-bed flats flat3: 1, // 3-bed flats flat4: 0, // 4-bed flats terracedHouse2: 0, // 2-bed terraced houses terracedHouse3: 2, // 3-bed terraced houses terracedHouse4: 1, // 4-bed terraced houses terracedHouse5: 0 // 5-bed terraced houses ); // Build cost data $buildCost = PropertyData::buildCost('SW1A 1AA'); // Rebuild cost calculator $rebuildCost = PropertyData::rebuildCost( postcode: 'SW1A 1AA', internalArea: 1200, siteQuality: 'good', propertyType: 'detached', complexity: 'standard', storeys: 2 );
📋 Planning & Regulatory Methods
use Lanos\LaravelPropertyData\Enums\DecisionRating; // Planning applications $planning = PropertyData::planningApplications( postcode: 'SW1A 1AA', decisionRating: DecisionRating::POSITIVE, category: 'residential', maxAge: 365 ); // Check if in Area of Outstanding Natural Beauty $aonb = PropertyData::aonb(postcode: 'SW1A 1AA'); // Check if in conservation area $conservation = PropertyData::conservationArea(postcode: 'SW1A 1AA'); // Check if in green belt $greenBelt = PropertyData::greenBelt(postcode: 'SW1A 1AA'); // Check if in national park $nationalPark = PropertyData::nationalPark(postcode: 'SW1A 1AA'); // Get listed buildings $listedBuildings = PropertyData::listedBuildings('SW1A 1AA');
📊 Area Information Methods
// Area type classification (rural/urban) $areaType = PropertyData::areaType('SW1A 1AA'); // Council tax information $councilTax = PropertyData::councilTax(postcode: 'SW1A 1AA'); // Crime statistics $crime = PropertyData::crime(postcode: 'SW1A 1AA'); // Demographics $demographics = PropertyData::demographics(postcode: 'SW1A 1AA'); // Flood risk $floodRisk = PropertyData::floodRisk(postcode: 'SW1A 1AA'); // Household income $income = PropertyData::householdIncome('SW1A 1AA'); // Internet speed $internetSpeed = PropertyData::internetSpeed('SW1A 1AA'); // Local Housing Allowance rate $lhaRate = PropertyData::lhaRate('SW1A 1AA'); // Population statistics $population = PropertyData::population('SW1A 1AA'); // Political representation $politics = PropertyData::politics('SW1A 1AA'); // PTAL score (London only) $ptal = PropertyData::ptal('SW1A 1AA'); // Key statistics by postcode $keyStats = PropertyData::postcodeKeyStats('SW1A 1AA');
🏪 Amenities Methods
// Nearby restaurants $restaurants = PropertyData::restaurants( postcode: 'SW1A 1AA', page: 1, perPage: 20 ); // Nearby schools $schools = PropertyData::schools(postcode: 'SW1A 1AA');
📄 Document Methods
// Land Registry documents $documents = PropertyData::landRegistryDocuments( title: 'DN123456', uprn: '123456789012' ); // Site plan documents $sitePlans = PropertyData::sitePlanDocuments('SW1A 1AA', page: 1, perPage: 20);
💳 Financial Calculators
// Mortgage calculator $mortgage = PropertyData::mortgageCalculator( price: 500000, deposit: 100000, rate: 5.5, termYears: 25 ); // Current mortgage rates $rates = PropertyData::mortgageRates(); // Stamp Duty calculator $stampDuty = PropertyData::stampDutyCalculator( price: 500000, buyerType: 'first-time' );
🔧 Account Methods
// Get API credits information $credits = PropertyData::accountCredits(); // Get account documents $documents = PropertyData::accountDocuments(page: 1, perPage: 20); // Test API connection $isConnected = PropertyData::testConnection();
Usage Examples
Example 1: Property Investment Analysis
use PropertyData; use Lanos\LaravelPropertyData\Enums\ProjectType; use Lanos\LaravelPropertyData\Enums\FinishQuality; class PropertyInvestmentService { public function analyzeInvestment(string $postcode, float $purchasePrice) { // Get current market data $prices = PropertyData::prices($postcode); $yields = PropertyData::yields($postcode); $demand = PropertyData::demand(postcode: $postcode); // Get area information $crime = PropertyData::crime(postcode: $postcode); $schools = PropertyData::schools(postcode: $postcode); $demographics = PropertyData::demographics(postcode: $postcode); // Calculate development potential $feasibility = PropertyData::developmentCalculator( postcode: $postcode, purchasePrice: $purchasePrice, sqftPreDevelopment: 1000, sqftPostDevelopment: 1400, projectType: ProjectType::REFURBISH, finishQuality: FinishQuality::MEDIUM ); return [ 'market' => [ 'prices' => $prices, 'yields' => $yields, 'demand' => $demand, ], 'area' => [ 'crime' => $crime, 'schools' => $schools, 'demographics' => $demographics, ], 'development' => $feasibility, ]; } }
Example 2: Property Due Diligence
use PropertyData; class PropertyDueDiligenceService { public function performDueDiligence(string $uprn) { // Get property details $property = PropertyData::uprn($uprn); $title = PropertyData::uprnTitle($uprn); // Get planning information $planning = PropertyData::planningApplications( postcode: $property['postcode'] ); // Check restrictions $checks = [ 'conservation_area' => PropertyData::conservationArea( postcode: $property['postcode'] ), 'green_belt' => PropertyData::greenBelt( postcode: $property['postcode'] ), 'listed_buildings' => PropertyData::listedBuildings( $property['postcode'] ), 'flood_risk' => PropertyData::floodRisk( postcode: $property['postcode'] ), ]; // Get documents $documents = PropertyData::landRegistryDocuments( uprn: $uprn ); return [ 'property' => $property, 'title' => $title, 'planning' => $planning, 'restrictions' => $checks, 'documents' => $documents, ]; } }
Example 3: Location-Based Search
use PropertyData; class LocationSearchService { public function searchByCoordinates(float $lat, float $lng) { $location = "$lat,$lng"; // Get area data using coordinates $demand = PropertyData::demand(location: $location); $agents = PropertyData::agents(location: $location); $crime = PropertyData::crime(location: $location); $restaurants = PropertyData::restaurants(location: $location); $schools = PropertyData::schools(location: $location); return compact('demand', 'agents', 'crime', 'restaurants', 'schools'); } public function searchByWhat3Words(string $w3w) { // Get area data using What3Words $demand = PropertyData::demand(w3w: $w3w); $planning = PropertyData::planningApplications(w3w: $w3w); return compact('demand', 'planning'); } }
Error Handling
The package includes comprehensive error handling with specific exception types:
Exception Types
PropertyDataApiException
- Base exception for all API errorsPropertyDataAuthenticationException
- Invalid API key or authentication failedPropertyDataConnectionException
- Network connection issuesPropertyDataServerException
- API server errors (5xx responses)PropertyDataRateLimitException
- Rate limit exceeded (currently unused as API has no rate limits)
Handling Exceptions
use Lanos\LaravelPropertyData\Exceptions\PropertyDataAuthenticationException; use Lanos\LaravelPropertyData\Exceptions\PropertyDataConnectionException; use Lanos\LaravelPropertyData\Exceptions\PropertyDataApiException; try { $data = PropertyData::prices('SW1A 1AA'); } catch (PropertyDataAuthenticationException $e) { // Handle authentication error Log::error('Invalid API key: ' . $e->getMessage()); } catch (PropertyDataConnectionException $e) { // Handle connection error Log::error('Connection failed: ' . $e->getMessage()); } catch (PropertyDataApiException $e) { // Handle general API error Log::error('API error: ' . $e->getMessage()); }
Input Validation
The package validates all inputs before making API calls:
try { // This will throw an InvalidArgumentException $data = PropertyData::prices('INVALID_POSTCODE'); } catch (\InvalidArgumentException $e) { // Handle validation error echo $e->getMessage(); // "Invalid UK postcode format..." }
Automatic Retry Logic
The package automatically retries failed requests for transient errors:
- Connection failures
- Server errors (5xx responses)
- Uses exponential backoff (1s, 2s, 4s...)
- Maximum 3 attempts by default
- Configurable via environment variables
Testing
Running Tests
composer test
Test Coverage
composer test-coverage
Static Analysis
composer analyse
Code Formatting
composer format
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details on how to contribute to this package.
Development Setup
- Fork the repository
- Clone your fork
- Install dependencies:
composer install
- Create a feature branch:
git checkout -b feature/my-feature
- Make your changes
- Run tests:
composer test
- Submit a pull request
Security
If you discover any security-related issues, please email contact@l4nos.dev instead of using the issue tracker.
Credits
License
The MIT License (MIT). Please see License File for more information.
Disclaimer
⚠️ IMPORTANT NOTICE
This package is an independent integration library for the PropertyData API. We are not affiliated with, endorsed by, or connected to PropertyData or its parent company.
- This package serves solely as a client interface to integrate with the PropertyData API
- We do not own, operate, or have any control over the PropertyData API
- All property data, valuations, and information are provided by PropertyData
- We are not responsible for the accuracy, completeness, or reliability of data returned by the API
- Users must obtain their own API key directly from PropertyData
For official API documentation and support, please visit https://propertydata.co.uk
Data Usage
Please ensure you comply with PropertyData's terms of service and data usage policies when using this package. The package authors assume no responsibility for how you use the data obtained through the API.
No Warranty
This package is provided "as is" without warranty of any kind, either expressed or implied. See the LICENSE file for full disclaimer of warranties.