Quickstart
Get an access token, then value a home. The samples include a shared sandbox credential, so you can copy, paste and run them without signing up. It takes under five minutes.
Before you start
You need curl, Node.js 20 or later, Python 3 with the requests package, or .NET 8.
The samples below already contain the sandbox credential:
- Client ID
cms_test_01m41mt4emh9n42nz9nx42ca3f_9txzn5k8- Client secret
cms_sk_2XhUy_1uBHY1YIvYhpfPFNXYFLpxvI9nucj3IpU3t4s
1. Get an access token
The API uses OAuth 2.0 client credentials. Exchange the client ID and secret for a token:
curl -X POST https://auth.checkmystreet.co.uk/oauth2/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d grant_type=client_credentials \
-d client_id=cms_test_01m41mt4emh9n42nz9nx42ca3f_9txzn5k8 \
-d client_secret=cms_sk_2XhUy_1uBHY1YIvYhpfPFNXYFLpxvI9nucj3IpU3t4s
const tokenRes = await fetch("https://auth.checkmystreet.co.uk/oauth2/token", {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "client_credentials",
client_id: "cms_test_01m41mt4emh9n42nz9nx42ca3f_9txzn5k8",
client_secret: "cms_sk_2XhUy_1uBHY1YIvYhpfPFNXYFLpxvI9nucj3IpU3t4s",
}),
});
const { access_token } = await tokenRes.json();
import requests
token_res = requests.post(
"https://auth.checkmystreet.co.uk/oauth2/token",
data={
"grant_type": "client_credentials",
"client_id": "cms_test_01m41mt4emh9n42nz9nx42ca3f_9txzn5k8",
"client_secret": "cms_sk_2XhUy_1uBHY1YIvYhpfPFNXYFLpxvI9nucj3IpU3t4s",
},
timeout=10,
)
token_res.raise_for_status()
access_token = token_res.json()["access_token"]
using System.Net.Http.Json;
using System.Text.Json;
var http = new HttpClient();
var tokenRes = await http.PostAsync(
"https://auth.checkmystreet.co.uk/oauth2/token",
new FormUrlEncodedContent(new Dictionary<string, string>
{
["grant_type"] = "client_credentials",
["client_id"] = "cms_test_01m41mt4emh9n42nz9nx42ca3f_9txzn5k8",
["client_secret"] = "cms_sk_2XhUy_1uBHY1YIvYhpfPFNXYFLpxvI9nucj3IpU3t4s",
}));
tokenRes.EnsureSuccessStatusCode();
var tokenJson = await tokenRes.Content.ReadFromJsonAsync<JsonElement>();
var accessToken = tokenJson.GetProperty("access_token").GetString();
The response holds the token and its lifetime in seconds:
{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 1800
}
Tokens last 30 minutes. Cache the token and reuse it until it expires, rather than requesting a new one for every call. Authentication covers caching and expiry.
For the curl samples, keep the token in a variable:
export TOKEN="paste-the-access-token-here"
2. Value a home
Send a POST to /partners/v1/valuations with the postcode, the property type and the number of bedrooms. This is the smallest valid request:
curl -X POST https://api.checkmystreet.co.uk/partners/v1/valuations \
-H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: 5f2b8c1e-4a7d-4e0b-9c61-2d8f3a90b7e4" \
-H "Content-Type: application/json" \
-d '{ "postcode": "M1 1AE", "propertyType": "flat", "bedrooms": 2 }'
const idempotencyKey = crypto.randomUUID(); // reuse this key if you retry
const res = await fetch("https://api.checkmystreet.co.uk/partners/v1/valuations", {
method: "POST",
headers: {
"Authorization": `Bearer ${access_token}`,
"Idempotency-Key": idempotencyKey,
"Content-Type": "application/json",
},
body: JSON.stringify({ postcode: "M1 1AE", propertyType: "flat", bedrooms: 2 }),
});
const valuation = await res.json();
console.log(valuation.valuation.estimate); // 425000
import uuid
idempotency_key = str(uuid.uuid4()) # reuse this key if you retry
res = requests.post(
"https://api.checkmystreet.co.uk/partners/v1/valuations",
headers={
"Authorization": f"Bearer {access_token}",
"Idempotency-Key": idempotency_key,
},
json={"postcode": "M1 1AE", "propertyType": "flat", "bedrooms": 2},
timeout=35,
)
valuation = res.json()
print(valuation["valuation"]["estimate"]) # 425000
var idempotencyKey = Guid.NewGuid().ToString(); // reuse this key if you retry
var request = new HttpRequestMessage(HttpMethod.Post,
"https://api.checkmystreet.co.uk/partners/v1/valuations")
{
Content = JsonContent.Create(new { postcode = "M1 1AE", propertyType = "flat", bedrooms = 2 }),
};
request.Headers.Authorization = new("Bearer", accessToken);
request.Headers.Add("Idempotency-Key", idempotencyKey);
var res = await http.SendAsync(request);
var valuation = await res.Content.ReadFromJsonAsync<JsonElement>();
Console.WriteLine(valuation.GetProperty("valuation").GetProperty("estimate")); // 425000
Send a new Idempotency-Key for each valuation you want, and reuse it only to retry that same request. However many times you retry with one key, you are charged once.
Request fields
| Field | Type | Required | Notes |
|---|---|---|---|
postcode | string | Yes | A full postcode in England or Wales. |
propertyType | string | Yes | One of detached, semi_detached, terraced, flat. |
bedrooms | integer | Yes, unless you send floorAreaSqm | Used to estimate the floor area. |
floorAreaSqm | number | No | Floor area in square metres, instead of bedrooms. |
yearBuilt | integer | No | The year the property was built. |
builtForm | string | No | Allowed values are in the API reference. |
wallsEnergyEfficiency | string | No | Allowed values are in the API reference. |
reference | string | No | Your own case number, echoed back in the response. |
include | array | No | commentary, rebuildCost or both. Free. See below. |
3. Read the result
A successful call returns 201 Created and the valuation. Figures are in pounds.
{
"id": "val_01j9xk2q7m4t8v6r3c5b0n1a2d",
"reference": "case-10492",
"valuedAt": "2026-11-03T10:15:02Z",
"valuation": {
"estimate": 425000,
"range": { "low": 381000, "high": 472000, "coverage": 0.81 },
"currency": "GBP",
"indexedTo": "2026-08"
},
"location": { "sector": "M1 1", "localAuthority": "E08000003" },
"dataQuality": "full",
"model": { "version": "2026-09-28T15:05:18Z" },
"input": { "postcode": "M1 1AE", "propertyType": "flat", "bedrooms": 2,
"floorAreaSqm": 57, "floorAreaSource": "bedrooms" },
"charge": { "credits": 10, "balanceAfter": 2490 }
}
Sandbox responses have the same shape, carry "mode": "test" and are never charged.
Low£381,000
Estimate£425,000
High£472,000
81% of past sales at this price level landed inside a range like this
| Field | What it tells you |
|---|---|
valuation.estimate | The middle figure. |
valuation.range | The low and high figures, and coverage: the share of past sales at this price level that landed inside a range like this one, in back-tests. |
valuation.indexedTo | The month the figures' price level stands at: the latest month the UK House Price Index had published for the area, usually about two months before valuedAt. The published past, not a forecast. |
location | The postcode sector and the ONS local authority code. |
dataQuality | How complete the property data behind the valuation was. |
model.version | The model build that produced the figures. |
input | What was valued, including anything we derived. Here the floor area came from the number of bedrooms. |
charge | Credits this call used, and your balance afterwards. |
Add commentary and the rebuild cost
Add include to the request for written commentary on the valuation and an indicative rebuild cost for buildings insurance. Both are free: the valuation costs 10 credits (10p) either way.
curl -X POST https://api.checkmystreet.co.uk/partners/v1/valuations \
-H "Authorization: Bearer $TOKEN" \
-H "Idempotency-Key: 3c9a6f04-1d2e-4b7a-8f53-6e0b1a7c9d28" \
-H "Content-Type: application/json" \
-d '{ "postcode": "M1 1AE", "propertyType": "semi_detached", "bedrooms": 3,
"include": ["commentary", "rebuildCost"] }'
The valuation comes back as above, with two more objects:
"commentary": {
"summary": "Based on the characteristics provided and current market data, the estimated market value of this semi-detached property (85 m²) in the M1 1 postcode sector is £425,000. ...",
"rangeWidth": "moderate",
"rangeNote": "The estimate range is moderate: ...",
"marketMomentum": "steady",
"areaInsights": { "growth": "...", "overview": "..." },
"disclaimer": "This estimate is produced by an automated statistical model ..."
},
"rebuildCost": {
"estimated": true,
"low": 196000, "typical": 231000, "high": 277000,
"pricesAsOf": "2026-06"
}
The commentary is written from fixed templates, not by AI. Show its disclaimer with it. The rebuild cost is for houses: a flat comes back with "estimated": false and "reason": "flat", because a flat is insured on the block's policy. It is worked out from the details you send, so we do not check the home's construction or whether it is listed. The reference lists every field.
Street analysis, with the same token
Every product uses the same token and error format. For what surrounds a postcode, send a GET; reading the same postcode again within 30 days is free:
curl https://api.checkmystreet.co.uk/partners/v1/street-analysis/M11AE \
-H "Authorization: Bearer $TOKEN"
The reference lists every field, and runs the request from the page.
4. Retry safely
The API stops any request that runs longer than 30 seconds. When a call fails in a way that is worth retrying, send it again with the same Idempotency-Key:
504 timeout: retry with the same key. You are charged at most once.503 data-unavailable: try again shortly. This is never charged.409 request-in-progress: the first call with this key is still running. Wait, then retry.429: slow down, and wait the number of seconds given inRetry-After. If itscodeisdaily_limit, stop until midnight UTC.
Limits and retries has the full policy.
Next steps
- Testing: use magic postcodes to trigger each outcome before you go live.
- Products: what is live now, and what comes next on the same token, headers and error format.
- Get access: request your own test credentials, then go live after a first top-up by card.
- Errors: every error type, what causes it and what to do.
- API reference: every endpoint and field, from
openapi.json.