API Documentation

Integrate Gadsden Valuations into your applications. Request property valuations, run batch jobs, and manage your account programmatically.

Base URL: https://gadsdenvaluations.com/api Version: v1 Format: JSON

Authentication

All API requests require a Bearer token in the Authorization header. API keys are prefixed with gak_ and can be created from your dashboard or via the API.

Authorization: Bearer gak_your_api_key_here

Getting your API key

  1. Create an account at gadsdenvaluations.com
  2. Go to your dashboard and enable API access
  3. Create an API key — store it securely, it is only shown once
  4. Purchase valuations to get started

You can have up to 5 active API keys per account. Keys can be revoked at any time and take effect immediately.

Quick Start

Request your first valuation in under a minute:

curl -X POST https://gadsdenvaluations.com/api/v1/valuations \
  -H "Authorization: Bearer gak_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"postcode": "M20 2TG", "address": "Wilmslow Road"}'

The response includes a point estimate, confidence tier, valuation range, comparable evidence, and the features that drove the valuation.

Rate Limits

API requests are rate-limited per account using a sliding window. The default limit is 60 requests per minute. When the limit is exceeded, the API returns 429 Too Many Requests:

{
  "error": "Rate limit exceeded",
  "limit": 60,
  "retry_after": 60
}

Wait for the retry_after period (in seconds) before making additional requests. Contact us if you need a higher rate limit for production integrations.

POST /v1/valuations

Request a valuation for a single property. Identify the property by UPRN, postcode + address, or internal property ID. Consumes 1 valuation from your balance on success. No charge for no-value responses.

Request body

ParameterTypeRequiredDescription
uprninteger*Unique Property Reference Number. Preferred identifier — unambiguous.
postcodestring*UK postcode (e.g. "M20 2TG"). Use with address for best results.
addressstringNoPartial address to disambiguate when using postcode. Matched with ILIKE.
property_idinteger*Internal Gadsden property ID (from a previous valuation response).

* At least one of uprn, postcode, or property_id is required.

Success response (200)

{
  "valuation_id": 1042,
  "status": "success",
  "property_id": 58291,
  "uprn": "100012345678",
  "predicted_value": 347500,
  "valuation_range": {
    "low": 301700,
    "high": 393300
  },
  "confidence": {
    "level": 2,
    "tier": 1,
    "fsd": 0.08,
    "fsd_band": "A",
    "fitch_haircut": 0.025,
    "description": "High confidence"
  },
  "property": {
    "address": "42 Wilmslow Road, Didsbury",
    "type": "Semi-Detached",
    "postcode": "M20 2TG",
    "bedrooms": 3,
    "floor_area_sqm": 95.0,
    "construction_period": "1919-1945",
    "epc_rating": "D",
    "last_sale": {
      "date": "2019-06-14",
      "price": 285000
    }
  },
  "comparables": [
    {
      "address": "38 Wilmslow Road, Didsbury",
      "distance_m": 42,
      "sale_date": "2025-11-20",
      "sale_price": 335000,
      "property_type": "S",
      "floor_area_sqm": 88.0
    }
  ],
  "feature_contributions": [
    {"feature": "floor_area_sqm", "contribution": 1842.5},
    {"feature": "latitude", "contribution": 1203.1},
    {"feature": "hpi_adjusted_price", "contribution": 987.3}
  ],
  "model_version": "v6",
  "processing_time_ms": 215
}

No-value response (200)

{
  "valuation_id": 1043,
  "status": "no_value",
  "valuation": null,
  "reason": "insufficient_comparables",
  "reason_description": "Fewer than 3 comparable sales within the search radius and time window",
  "missing_data": ["recent_comparables"],
  "property_id": 72014,
  "uprn": "200098765432",
  "model_version": "v6",
  "processing_time_ms": 87
}

GET /v1/valuations/{id}

Retrieve a previously completed valuation by its ID. Only returns valuations belonging to your account.

Path parameters

ParameterTypeDescription
idintegerThe valuation_id from a previous valuation response.

Response (200)

{
  "valuation_id": 1042,
  "property_id": 58291,
  "uprn": "100012345678",
  "address": "42 Wilmslow Road, Didsbury",
  "postcode": "M20 2TG",
  "predicted_value": 347500,
  "confidence_level": 2,
  "valuation_tier": 1,
  "status": "complete",
  "created_at": "2026-03-08T14:22:10.000000Z",
  "completed_at": "2026-03-08T14:22:10.000000Z"
}

POST /v1/valuations/batch

Request valuations for up to 100 properties in a single call. Each successful result consumes 1 valuation from your balance. No-value results and lookup failures are not charged.

Request body

ParameterTypeRequiredDescription
propertiesarrayYesArray of 1–100 property objects, each with the same fields as the single valuation endpoint.

Request example

{
  "properties": [
    {"uprn": 100012345678},
    {"postcode": "SW1A 1AA", "address": "Downing Street"},
    {"property_id": 58291}
  ]
}

Response (200)

{
  "results": [
    {
      "property_id": 58291,
      "predicted_value": 347500,
      "confidence": {
        "level": 2,
        "tier": 1,
        "fsd": 0.08,
        "fsd_band": "A",
        "fitch_haircut": 0.025,
        "description": "High confidence"
      },
      "status": "success"
    },
    {
      "property_id": 72014,
      "status": "no_value",
      "reason": "insufficient_comparables",
      "reason_description": "Fewer than 3 comparable sales within the search radius and time window",
      "missing_data": ["recent_comparables"]
    },
    {
      "input": {"postcode": "INVALID"},
      "error": "Property not found"
    }
  ],
  "total": 3
}

The batch endpoint pre-checks your valuation balance against the total number of properties. If your balance is lower than the batch size, the request is rejected with a 402 before any valuations are attempted.

Individual failures (property not found, no-value, AVM errors) do not halt the batch — remaining properties continue processing. However, if your balance runs out mid-batch, processing stops.

GET /v1/account

Retrieve your account details including current valuation balance and rate limit.

Response (200)

{
  "user_id": 12,
  "email": "developer@lender.co.uk",
  "plan_type": "standard",
  "valuation_balance": 487,
  "api_enabled": true,
  "api_rate_limit": 60
}

If your account belongs to an organisation, valuation_balance reflects the shared organisation pool.

GET /v1/keys

List all API keys associated with your account, including revoked keys.

Response (200)

{
  "keys": [
    {
      "id": 1,
      "key_prefix": "gak_Hp8z0eK1",
      "name": "Production",
      "last_used_at": "2026-03-08T12:30:00.000000Z",
      "created_at": "2026-01-15T10:00:00.000000Z",
      "revoked_at": null
    },
    {
      "id": 2,
      "key_prefix": "gak_Qm4xWr7p",
      "name": "Staging",
      "last_used_at": null,
      "created_at": "2026-02-20T09:15:00.000000Z",
      "revoked_at": "2026-03-01T14:00:00.000000Z"
    }
  ]
}

POST /v1/keys

Create a new API key. Maximum 5 active keys per account. The full key is only returned once — store it securely.

Request body

ParameterTypeRequiredDescription
namestringNoA label for this key (max 100 characters). E.g. "Production", "Staging".

Response (201)

{
  "id": 3,
  "key": "gak_Hp8z0eK1q7X9pL2m4R6sT8uV0wY2zA4bCdEfGhIjKl",
  "key_prefix": "gak_Hp8z0eK1",
  "name": "Production",
  "message": "Store this key securely. It will not be shown again."
}

DELETE /v1/keys/{id}

Revoke an API key. Takes effect immediately — any in-flight requests using this key will fail.

Path parameters

ParameterTypeDescription
idintegerThe key ID (from the list keys response).

Response (200)

{
  "message": "API key revoked"
}

Response Fields Reference

Complete field reference for the valuation response object.

FieldTypeDescription
valuation_idintegerUnique identifier for this valuation request. Use to retrieve later via GET /v1/valuations/:id.
statusstring"success" or "no_value". A success means the model produced a valuation. A no-value means the property could not be reliably valued.
property_idintegerInternal Gadsden property ID. Stable across requests — can be reused for future valuations.
uprnstringUnique Property Reference Number (Ordnance Survey).
predicted_valueintegerPoint estimate of market value in GBP. Only present when status is "success".

valuation_range

FieldTypeDescription
lowintegerLower bound of the 90% prediction interval (GBP). Calculated as predicted_value × (1 − 1.645 × FSD).
highintegerUpper bound of the 90% prediction interval (GBP). Calculated as predicted_value × (1 + 1.645 × FSD).

confidence

FieldTypeDescription
tierintegerConfidence tier: 1 (High), 2 (Medium), 3 (Low). Drives the FSD and haircut band.
levelintegerUnderlying confidence level score from the model.
fsdfloatForecast Standard Deviation. The model's estimate of its own prediction error for this property.
fsd_bandstringFitch/EAA haircut band: "A", "B", "C", or "D".
fitch_haircutfloatHaircut percentage for this band (e.g. 0.025 = 2.5%).
descriptionstringHuman-readable tier label: "High confidence", "Medium confidence", "Low confidence".

property

FieldTypeDescription
addressstringFull property address.
typestringProperty type (e.g. Detached, Semi-Detached, Terraced, Flat, Maisonette, Bungalow).
postcodestringUK postcode.
bedroomsintegerNumber of bedrooms (may be model-predicted if not in source data).
floor_area_sqmfloatTotal floor area in square metres (from EPC data where available).
construction_periodstringConstruction age band (e.g. "1919-1945", "2007-onwards").
epc_ratingstringCurrent EPC rating (A–G).
last_sale.datestringDate of most recent Land Registry transaction (ISO 8601).
last_sale.priceintegerPrice paid at last transaction (GBP).

comparables

Array of up to 5 comparable property sales used as market evidence. Each comparable includes:

FieldTypeDescription
addressstringComparable property address.
distance_mintegerDistance from subject property in metres.
sale_datestringDate of sale (ISO 8601).
sale_priceintegerTransaction price (GBP).
property_typestringLand Registry type code: D (Detached), S (Semi), T (Terraced), F (Flat).
floor_area_sqmfloatFloor area of the comparable (where available).

feature_contributions

Array of up to 10 features showing what most influenced the valuation. Each entry has:

FieldTypeDescription
featurestringFeature name (e.g. floor_area_sqm, latitude, hpi_adjusted_price).
contributionfloatFeature importance score (LightGBM gain). Higher values indicate greater influence on the valuation.

Confidence Scoring & FSD

Every valuation includes a per-property confidence score. This maps to the European AVM Alliance Forecast Standard Deviation (FSD) scale used by ratings agencies (Fitch, S&P) for RMBS analysis.

Confidence TierFSDBandFitch HaircutDescription
10.08 (8%)A2.5%High confidence — strong comparable evidence, complete property data
20.12 (12%)B5%Medium confidence — reasonable evidence, some data gaps
30.20 (20%)C10%Low confidence — limited evidence or significant data gaps
NoneD20%Below threshold — returned as a no-value response

The valuation_range (low/high) is derived from the FSD: predicted_value × (1 ± 1.645 × FSD), giving a 90% prediction interval.

For lender integration, the confidence tier and FSD band allow you to apply your own risk policy — for example, accepting Tier 1 and 2 valuations for low-LTV lending and escalating Tier 3 for physical survey.

No-Value Responses

The API will decline to value a property when there is insufficient data for a reliable estimate. No-value responses return status: "no_value" with HTTP 200 and are not charged.

Reason codes

ReasonDescription
missing_critical_dataFloor area, bedrooms, and property type are all unknown. The model cannot produce a meaningful estimate without at least one physical characteristic.
insufficient_comparablesFewer than 3 comparable sales found within the search radius (2km) and time window (5 years). Typical for very rural or unusual properties.
below_confidence_thresholdThe model produced an estimate but the confidence score was below the minimum threshold. The estimate was discarded rather than returned with inadequate confidence.

The missing_data array provides additional detail about what data was absent, helping you determine whether a no-value is resolvable (e.g. by supplying a UPRN instead of an approximate postcode match).

See our No-Value Policy for the full methodology behind valuation refusal.

Error Handling

The API uses standard HTTP status codes. Error responses include a JSON body with an error field.

StatusMeaningExample error message
400Bad request — missing required parameters or invalid input"property_id, uprn, or postcode+address required"
401Authentication failed — missing, invalid, or revoked API key"Missing or invalid Authorization header"
402Insufficient valuations to complete the request"Insufficient valuations"
403API access disabled on your account"API access disabled"
404Property not found in our database"Property not found"
422Validation error — request body failed validation rulesLaravel validation error object
429Rate limit exceeded"Rate limit exceeded" with retry_after: 60
503AVM service temporarily unavailable"AVM service unavailable"

Error response format

{
  "error": "Insufficient valuations"
}

For 429 responses, the body also includes limit and retry_after fields:

{
  "error": "Rate limit exceeded",
  "limit": 60,
  "retry_after": 60
}

Billing

Valuations are pay-per-use. No subscription required — purchased valuations never expire.

  • 1 valuation deducted per successful request (single or batch)
  • No charge for no-value responses, property-not-found errors, or failed lookups
  • Batch pre-check: the batch endpoint checks your balance against the total batch size before starting. If insufficient, the entire batch is rejected with 402.
  • Organisation accounts: valuations are pooled across the organisation. Any member can draw from the shared balance.

Purchase valuations from the pricing page or your dashboard. Check your current balance programmatically with GET /v1/account.

Testing

There are two ways to evaluate the API without committing to production volumes:

Free backtesting

Upload a CSV of properties where you already know the sale price. Our backtest tool will run valuations against your data and produce a comparison report showing accuracy metrics (MdAPE, PE10, PE15, PE20) broken down by property type, price band, and region. Backtesting is free — no credit card required.

This is the recommended approach for lender evaluation. Test our model against your own portfolio data and take the comparison report to your risk committee.

Single valuations

Purchase a small valuation bundle and make individual API calls. The smallest bundle starts at £9.95. No-value responses are free, so you can test address resolution and property lookup without being charged.

Code Examples

cURL

# Single valuation by UPRN
curl -X POST https://gadsdenvaluations.com/api/v1/valuations \
  -H "Authorization: Bearer gak_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"uprn": 100012345678}'

# Single valuation by postcode + address
curl -X POST https://gadsdenvaluations.com/api/v1/valuations \
  -H "Authorization: Bearer gak_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"postcode": "M20 2TG", "address": "Wilmslow Road"}'

# Batch valuation
curl -X POST https://gadsdenvaluations.com/api/v1/valuations/batch \
  -H "Authorization: Bearer gak_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{"properties": [{"uprn": 100012345678}, {"postcode": "SW1A 1AA"}]}'

# Check valuation balance
curl https://gadsdenvaluations.com/api/v1/account \
  -H "Authorization: Bearer gak_your_api_key_here"

Python

import requests

API_KEY = "gak_your_api_key_here"
BASE_URL = "https://gadsdenvaluations.com/api/v1"
HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

# Single valuation
response = requests.post(
    f"{BASE_URL}/valuations",
    headers=HEADERS,
    json={"postcode": "M20 2TG", "address": "Wilmslow Road"},
)
data = response.json()

if data["status"] == "success":
    print(f"Value: £{data['predicted_value']:,}")
    print(f"Range: £{data['valuation_range']['low']:,} – £{data['valuation_range']['high']:,}")
    print(f"Confidence: Tier {data['confidence']['tier']} ({data['confidence']['fsd_band']})")
elif data["status"] == "no_value":
    print(f"No value: {data['reason_description']}")

# Batch valuation
batch_response = requests.post(
    f"{BASE_URL}/valuations/batch",
    headers=HEADERS,
    json={
        "properties": [
            {"uprn": 100012345678},
            {"postcode": "SW1A 1AA"},
            {"postcode": "M1 1AA", "address": "Piccadilly"},
        ]
    },
)
for result in batch_response.json()["results"]:
    if result.get("status") == "success":
        print(f"Property {result['property_id']}: £{result['predicted_value']:,}")
    elif result.get("status") == "no_value":
        print(f"Property {result['property_id']}: no value ({result['reason']})")
    else:
        print(f"Error: {result.get('error')}")

# Check valuation balance
account = requests.get(f"{BASE_URL}/account", headers=HEADERS).json()
print(f"Valuations remaining: {account['valuation_balance']}")

Node.js

const API_KEY = "gak_your_api_key_here";
const BASE_URL = "https://gadsdenvaluations.com/api/v1";

async function valuate(postcode, address) {
  const response = await fetch(`${BASE_URL}/valuations`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ postcode, address }),
  });

  if (!response.ok) {
    const err = await response.json();
    throw new Error(`${response.status}: ${err.error}`);
  }

  return response.json();
}

// Single valuation
const data = await valuate("M20 2TG", "Wilmslow Road");
if (data.status === "success") {
  console.log(`Value: £${data.predicted_value.toLocaleString()}`);
  console.log(`Confidence: Tier ${data.confidence.tier} (${data.confidence.fsd_band})`);
} else {
  console.log(`No value: ${data.reason_description}`);
}

// Check valuation balance
const account = await fetch(`${BASE_URL}/account`, {
  headers: { Authorization: `Bearer ${API_KEY}` },
}).then((r) => r.json());
console.log(`Valuations: ${account.valuation_balance}`);

PHP (Guzzle)

use GuzzleHttp\Client;

$client = new Client([
    'base_uri' => 'https://gadsdenvaluations.com/api/v1/',
    'headers' => [
        'Authorization' => 'Bearer gak_your_api_key_here',
        'Content-Type' => 'application/json',
    ],
]);

// Single valuation
$response = $client->post('valuations', [
    'json' => ['postcode' => 'M20 2TG', 'address' => 'Wilmslow Road'],
]);
$data = json_decode($response->getBody(), true);

if ($data['status'] === 'success') {
    echo "Value: £" . number_format($data['predicted_value']) . "\n";
    echo "Range: £" . number_format($data['valuation_range']['low'])
       . " – £" . number_format($data['valuation_range']['high']) . "\n";
    echo "Confidence: Tier {$data['confidence']['tier']} ({$data['confidence']['fsd_band']})\n";
} elseif ($data['status'] === 'no_value') {
    echo "No value: {$data['reason_description']}\n";
}

// Batch valuation
$batchResponse = $client->post('valuations/batch', [
    'json' => [
        'properties' => [
            ['uprn' => 100012345678],
            ['postcode' => 'SW1A 1AA'],
        ],
    ],
]);
$batch = json_decode($batchResponse->getBody(), true);

foreach ($batch['results'] as $result) {
    if (($result['status'] ?? null) === 'success') {
        echo "Property {$result['property_id']}: £" . number_format($result['predicted_value']) . "\n";
    }
}

// Check balance
$account = json_decode($client->get('account')->getBody(), true);
echo "Valuations: {$account['valuation_balance']}\n";

OpenAPI Specification

A machine-readable OpenAPI 3.0 specification is available for code generation and API client tooling.

curl https://gadsdenvaluations.com/api/v1/openapi.json | python -m json.tool

Use this to auto-generate client libraries with tools like OpenAPI Generator, or import directly into Postman.

Further Reading

This site uses essential cookies and Google Analytics. See our Privacy Policy.