Client libraries
Official libraries for TypeScript, Python, and .NET handle authentication, rate-limit retries, enrichment-pending logic, and quota header parsing automatically. For every other language, the API is standard HTTP.
All requests require X-Api-Key: YOUR_API_KEY.
Your key is in your dashboard.
Keys are prefixed ea_live_.
TypeScript / Node.js
Install from npm. Requires Node 20+. Full type definitions included. GitHub
npm install @zyfy-uk/zyfyimport { Zyfy } from '@zyfy-uk/zyfy';
const client = new Zyfy(); // reads ZYFY_API_KEY from env
const postcode = await client.postcode.lookup('SW1A 2AA');
console.log(postcode.signals?.crime?.rateBand); // "high"
console.log(postcode.summary?.propertyRiskLevel); // "low"
console.log(postcode.quota.remaining); // 9999
const vehicle = await client.vehicle.lookup('AB12CDE');
console.log(vehicle.summary?.buyRecommendation); // "good"
console.log(vehicle.signals?.odometerTrend); // "consistent"
// Nearest postcode to a coordinate
const nearest = await client.postcode.nearest(51.5034, -0.1276);
console.log(nearest.postcode); // "SW1A 2AA"
console.log(nearest.queryPointDistanceMetres); // 87.3
// Every postcode within 500 m (Starter and above)
const zone = await client.postcode.within(51.5034, -0.1276, { radius: 500 });
console.log(zone.total); // number of postcodes returned
console.log(zone.results[0].postcode); // closest postcodePython
Install from PyPI. Supports both sync and async (AsyncZyfy) usage. Requires Python 3.9+. GitHub
pip install zyfyfrom zyfy import Zyfy
with Zyfy() as client: # reads ZYFY_API_KEY from env
postcode = client.postcode.lookup('SW1A 2AA')
print(postcode.signals.crime.rate_band if postcode.signals and postcode.signals.crime else None)
print(postcode.quota.remaining)
vehicle = client.vehicle.lookup('AB12CDE')
print(vehicle.summary.buy_recommendation if vehicle.summary else None)
# Nearest postcode to a coordinate
nearest = client.postcode.nearest(51.5034, -0.1276)
print(nearest.postcode, nearest.query_point_distance_metres)
# Every postcode within 500 m (Starter and above)
zone = client.postcode.within(51.5034, -0.1276, radius=500)
for pc in zone.results:
print(pc.postcode, pc.query_point_distance_metres).NET
Install from NuGet. Targets netstandard2.0 — compatible with .NET 6+, .NET Framework 4.6.1+, and VB.NET. Sync and async methods on every resource. GitHub
dotnet add package Zyfyusing Zyfy;
var client = new ZyfyClient(); // reads ZYFY_API_KEY from env
var postcode = await client.Postcode.LookupAsync("SW1A 2AA");
Console.WriteLine(postcode.Signals?.Crime?.RateBand); // "very_high"
Console.WriteLine(postcode.Summary?.LiveabilityLevel); // "low"
Console.WriteLine(postcode.Quota?.Remaining); // 9999
var vehicle = await client.Vehicle.LookupAsync("AB12CDE");
Console.WriteLine(vehicle.Summary?.BuyRecommendation); // "good"
Console.WriteLine(vehicle.Signals?.OdometerTrend); // "consistent"
// Nearest postcode to a coordinate
var nearest = await client.Postcode.NearestAsync(51.5034, -0.1276);
Console.WriteLine(nearest.Postcode); // "SW1A 2AA"
Console.WriteLine(nearest.QueryPointDistanceMetres); // 87.3
// Every postcode within 500 m (Starter and above)
var zone = await client.Postcode.WithinAsync(51.5034, -0.1276, radius: 500);
Console.WriteLine(zone.Total); // number of postcodes returned
Console.WriteLine(zone.Results[0].Postcode); // closest postcode
// Sync variant — all methods have a sync counterpart
var v = client.Vehicle.Lookup("AB12CDE");Other languages — raw HTTP
The API is standard HTTP. These examples show the patterns to handle manually: authentication, rate limiting, and enrichment-pending retries.
curl
curl "https://zyfy.uk/v1/postcode/SW1A+2AA" \
-H "X-Api-Key: YOUR_API_KEY"curl https://zyfy.uk/v1/vehicle/AB12CDE \
-H "X-Api-Key: YOUR_API_KEY"Node.js — without the SDK
Uses built-in fetch (Node 18+). If you prefer not to use the npm package, this covers the retry patterns you'd need to implement yourself.
const KEY = process.env.ZYFY_API_KEY;
async function zyfy(path) {
const res = await fetch(`https://zyfy.uk/v1/${path}`, {
headers: { 'X-Api-Key': KEY }
});
if (res.status === 429) {
const wait = parseInt(res.headers.get('Retry-After') || '5', 10);
await new Promise(r => setTimeout(r, wait * 1000));
return zyfy(path);
}
if (!res.ok) throw new Error(`Zyfy ${res.status}`);
const data = await res.json();
if (data.enrichmentPending) {
const wait = parseInt(res.headers.get('Retry-After') || '5', 10);
await new Promise(r => setTimeout(r, wait * 1000));
return zyfy(path);
}
return data;
}
const postcode = await zyfy('postcode/SW1A%202AA');
const vehicle = await zyfy('vehicle/AB12CDE');
console.log(postcode.signals.crime.rateBand); // "high"
console.log(postcode.summary.propertyRiskLevel); // "low"
console.log(vehicle.summary.buyRecommendation); // "good"
console.log(vehicle.signals.odometerTrend); // "consistent"Python — without the SDK
Requires httpx — pip install httpx. If you prefer raw HTTP over the PyPI package.
import os, time, httpx
KEY = os.environ["ZYFY_API_KEY"]
def zyfy(path: str) -> dict:
headers = {"X-Api-Key": KEY}
for _ in range(5):
r = httpx.get(f"https://zyfy.uk/v1/{path}", headers=headers)
if r.status_code == 429:
time.sleep(int(r.headers.get("Retry-After", "5")))
continue
r.raise_for_status()
data = r.json()
if data.get("enrichmentPending"):
time.sleep(int(r.headers.get("Retry-After", "5")))
continue
return data
raise RuntimeError("Max retries exceeded")
postcode = zyfy("postcode/SW1A%202AA")
vehicle = zyfy("vehicle/AB12CDE")PHP
Uses cURL — available in all standard PHP installations.
<?php
$key = getenv('ZYFY_API_KEY');
function zyfy(string $path, string $key): array {
for ($i = 0; $i < 5; $i++) {
$ch = curl_init("https://zyfy.uk/v1/{$path}");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => true,
CURLOPT_HTTPHEADER => ["X-Api-Key: {$key}"],
]);
$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
curl_close($ch);
$body = json_decode(substr($response, $header_size), true);
if ($status === 429 || ($status === 200 && ($body['enrichmentPending'] ?? false))) {
sleep(5);
continue;
}
if ($status !== 200) throw new RuntimeException("Zyfy {$status}");
return $body;
}
throw new RuntimeException("Max retries exceeded");
}
$postcode = zyfy('postcode/SW1A%202AA', $key);
$vehicle = zyfy('vehicle/AB12CDE', $key);See Errors & quotas for full rate limit header documentation.