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
npm install @zyfy-uk/zyfy
TypeScript / Node.js
import { 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 postcode

Python

Install from PyPI. Supports both sync and async (AsyncZyfy) usage. Requires Python 3.9+. GitHub

pip
pip install zyfy
Python
from 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 CLI
dotnet add package Zyfy
C#
using 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

Postcode lookup
curl "https://zyfy.uk/v1/postcode/SW1A+2AA" \
  -H "X-Api-Key: YOUR_API_KEY"
Vehicle lookup
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.

Node.js
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 httpxpip install httpx. If you prefer raw HTTP over the PyPI package.

Python
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
<?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.