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. Buy any bundle of 10 or more valuations — API access is enabled automatically. Or contact us to request it.
  3. Create an API key in the API Access section of your dashboard — store it securely, it is only shown once

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": "Dene Road"}'

The response includes a point estimate, FSD-based confidence band, 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,
    "fsd": 0.08,
    "fsd_band": "A",
    "fitch_haircut": 0.025,
    "fitch_haircut_pct": 2.5
  },
  "property": {
    "address": "42 Dene 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 Dene 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 Dene Road, Didsbury",
  "postcode": "M20 2TG",
  "predicted_value": 347500,
  "confidence_level": 2,
  "fsd_band": "A",
  "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,
        "fsd": 0.08,
        "fsd_band": "A",
        "fitch_haircut": 0.025,
        "fitch_haircut_pct": 2.5
      },
      "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
levelintegerUnderlying confidence level score from the model.
fsdfloatForecast Standard Deviation. The model's estimate of its own prediction error for this property. Drives both the valuation range and the classification band.
fsd_bandstringFitch/EAA classification band derived from FSD: "A" (FSD ≤ 0.05), "B" (≤ 0.10), "C" (≤ 0.20), or "D" (> 0.20).
fitch_haircutfloatThe haircut fraction Fitch’s published RMBS criteria associate with the band (e.g. 0.025 = 2.5%). Provided for reference to Fitch’s framework only — not a Gadsden Valuations recommendation.
fitch_haircut_pctfloatThe same Fitch reference figure as a percentage (e.g. 2.5).

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 carries a per-property Forecast Standard Deviation (FSD) — the model's estimate of its own prediction error. FSD is the European AVM Alliance metric used by Fitch and S&P for RMBS analysis and is the sole confidence expression in the API response.

FSD is derived from a granular lookup (decile × property type × price band) calibrated against realised Land Registry sales, and is mapped to a Fitch RMBS classification band:

BandFSD range
A≤ 0.05
B0.05 – 0.10
C0.10 – 0.20
D> 0.20

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

For lender integration, fsd_band lets you apply your own risk policy — for example, accepting Bands A and B for low-LTV lending and escalating Band D 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.

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": "Dene 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": "Dene 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"FSD band: {data['confidence']['fsd_band']} (FSD {data['confidence']['fsd']})")
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", "Dene Road");
if (data.status === "success") {
  console.log(`Value: £${data.predicted_value.toLocaleString()}`);
  console.log(`FSD band: ${data.confidence.fsd_band} (FSD ${data.confidence.fsd})`);
} 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' => 'Dene 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 "FSD band: {$data['confidence']['fsd_band']} (FSD {$data['confidence']['fsd']})\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.