Skip to main content

← Data Services

MyTapWater → PDTF mapping

How MyTapWater data maps onto the Property Data Trust Framework (PDTF), the

Open Property Data Association's open schema for residential property data

exchange in England & Wales.

Latest release verified v3.5.0 (2025-08-28), schema line v3 stable.

Repo: <https://github.com/Property-Data-Trust-Framework/schemas>.

Shape

PDTF models a property as a transaction whose propertyPack holds property

data keyed by integer uprn. We emit a partial transaction:

{
  "$schema": "https://trust.propdata.org.uk/schemas/v3/pdtf-transaction.json",
  "transactionId": "mytapwater:<uprn|postcode>",
  "status": "provider-data",
  "propertyPack": {
    "uprn": <integer>,               // PDTF-native key
    "address": { "postcode": "...", "homeNation": "England|Wales" },
    "mytapwater": { …provider water dataset… }   // namespaced extension
  }
}

Why a mytapwater extension (not native PDTF fields)

PDTF has no native fields for tap-water quality, a composite water score, lead-pipe

likelihood, or storm-overflow proximity. PDTF v3's transaction schema sets **no

additionalProperties: false and explicitly supports custom overlays /

extensions** for provider-specific data (see src/schemas/v3/overlays/extensions

and exampleCustomOverlay in the schema repo). So provider data lives under a

single clearly-namespaced propertyPack.mytapwater key. This validates against the

base v3 schema (permissive) and is the PDTF-sanctioned pattern — a platform engineer

reads propertyPack.uprn + propertyPack.mytapwater.* with no translation.

Water-relevant *native* PDTF structures exist (con29DW = CON29 Drainage & Water

overlay; searches/drainage-and-water) but they model conveyancing search answers,

not ongoing water-quality metrics — a poor fit for our data. We reference them in

provenance rather than forcing our data into them.

Field-by-field mapping

MyTapWater outputPDTF pathNotes
UPRNpropertyPack.uprn (integer)PDTF-native. Resolved from ONSUD (Dec 2025).
PostcodepropertyPack.address.postcoderesolved_postcode when input was a UPRN.
Nation (England/Wales)propertyPack.address.homeNationPDTF uses homeNation.
Water companypropertyPack.mytapwater.supply.waterCompany+ supplyZone, dataYear, populationServed.
Composite score (0–100) + label…mytapwater.waterQualityScore.{value,label}MyTapWater-derived; provenance flags derivation.
Water-quality parameters (pH, hardness, chlorine, nitrate, lead, fluoride, THM, copper, iron, nickel, arsenic, pesticides)…mytapwater.parameters.<param>.{min,mean,max,unit}Source: DWI / company statutory reports.
Lead-pipe likelihood (band + score)…mytapwater.leadPipeRiskPostcode-area likelihood, EPC-derived. Explicitly *not* property-level (see honesty note). null where no EPC evidence.
Hosepipe / water-use restrictions…mytapwater.restrictions.{status,scope,effectiveFrom}Company-level; provenance carries the company's own source_url.
Storm-overflow (sewage) proximity…mytapwater.sewage (reference block)Full nearest-outfall data served UPRN-keyed at /sewage-lookup?uprn=; needs geocoding so it is referenced, not inlined (keeps format=pdtf fast).
Live incidents…mytapwater.activeIncidents[]{type,severity,title,since}.
PFAS enforcement notices…mytapwater.pfasNotices[]Active notices only.

Provenance (verified-claims alignment)

Every data block carries a provenance object aligned to PDTF's verified-claims

vocabulary (src/schemas/verifiedClaims/pdtf-verified-claims.json, an OIDC-IA-style

model):

"provenance": {
  "trust_framework": "uk_open_data",
  "source": "Drinking Water Inspectorate / <company> statutory water-quality report",
  "data_year": 2025,
  "source_url": "https://…",          // where the underlying record lives
  "resolved_by": "MyTapWater API (mytapwater.co.uk)",
  "time": "2026-07-15T…Z"
}

This maps to PDTF verified-claims verification.{trust_framework,time} +

verification.evidence[].source. We use a flattened provenance object rather than

the full nested verification/claims envelope — see deviations.

Deliberate deviations (be honest with integrators)

full PDTF verifiedClaims[] envelope ({ claims, verification: { evidence: [...] } }).

Rationale: our provenance is dataset-level (a regulator/company report + our

derivation), not per-field attestations. A wrapper to full verified-claims is

trivial if an integrator needs it.

trust-framework identifier (PDTF's are aimed at identity/KYC frameworks).

overlay id — see above; validates against base v3 but is not an OPDA-approved overlay.

property granularity; our lead model is a postcode-area screen. The block's basis

field and propertyPack.mytapwater._note state this explicitly so no integrator

mistakes it for a property-level test.

/sewage-lookup?uprn=.

lifecycle enum (For sale, Sold subject to contract, …) that does not apply

to provider data, so we omit it (it is optional). Including a non-enum value

like provider-data is the only thing that fails v3 validation.

Validation

The emitted transaction validates against the base v3 pdtf-transaction.json

JSON Schema (permissive: no required fields, no additionalProperties:false;

propertyPack.uprn is integer, which we honour). The mytapwater.* extension is

not described by the base schema — that is expected for a namespaced extension and is

the intended deviation (item 3). A saved, validated example lives at

samples/pdtf-example-<uprn>.json.

Explore
🏢Water Companies 🛒Products 🏆Rankings 💧Hard Water Areas 📄Full Report 📰Press ⚗️PFAS Guide ℹ️About