PDTF overlays
An overlay is a JSON-Schema artefact that adds one form, search or document to the base PDTF transaction schema. Overlays are the unit of composition the schema package ships in — pick the ones your use case needs, merge them on top of the base, and you get a complete validating schema.
- 1 base transaction schema —
pdtf-transaction.json(not an overlay) - 18 main overlays in
v3/overlays/*.json - 16 extension overlays in
v3/overlays/extensions/*.json(modular NTS2 pieces) - 34 overlay files total in PDTF v3
combined.json and skeleton.json at the v3 root aren't
overlays — the first is a pre-merged convenience view, the second is a starter
template for empty transactions.
What an overlay is — and is not
An overlay is a draft-07 JSON Schema that mirrors the shape of the base transaction but only specifies what it adds or constrains. The merge function turns the base + overlays into a complete schema.
| Dimension | Overlay | Bounded context (DDD) |
|---|---|---|
| Layer | Schema layer — JSON Schema files | Domain layer — language and rules of a business function |
| Granularity | One form, search or document (BASPI, TA6, CON29R …) | An entire industry function (Estate Agency, Conveyancing …) |
| Lives in | v3/overlays/*.json in the schemas repo | Architecture documentation (see Bounded contexts) |
| Who picks it | Developer assembling a runtime schema | Business architect modelling the domain |
| Cardinality | Many overlays per bounded context | One bounded context owns several overlays |
Overlays predate the DDD analysis — the bounded-context model is a retrofit onto a partition that was already there. So the answer to "are overlays the same as bounded contexts?" is: no, but they map cleanly onto them.
The catalogue
Main overlays (18)
Bounded context is the business domain the overlay belongs to (one of six). Status is the lifecycle state of the overlay file: active means current, superseded / legacy means a newer overlay covers the same form but the older one is still shipped in v3 for backward compatibility. The two are orthogonal — every legacy overlay still belongs to its original bounded context.
Property information forms
What the seller declares about the property.
| Form | File | Version | Bounded context | Status |
|---|---|---|---|---|
| Buyers and Sellers Property Information | baspi5.json | v5.0 | Estate Agency | active |
| Buyers and Sellers Property Information | baspi4.json | v4.0 | Estate Agency | superseded by baspi5 |
| NTS Material Information (Sales) | nts2.json | 2025 | Estate Agency | active |
| NTS Material Information (Sales) | nts.json | 2023 | Estate Agency | legacy — superseded by nts2 |
| NTS Material Information (Lettings) | ntsl2.json | 2025 | Estate Agency | active |
| NTS Material Information (Lettings) | ntsl.json | 2023 | Estate Agency | legacy — superseded by ntsl2 |
| Property Information Questionnaire | piq.json | v3 | Surveying | active |
Legal forms (Law Society)
What the conveyancer asks for.
| Form | File | Version | Bounded context | Status |
|---|---|---|---|---|
| Property Information Form | ta6.json | Edition 4 | Conveyancing | active |
| Leasehold Information Form | ta7.json | Edition 3 | Conveyancing | active |
| Fittings and Contents Form | ta10.json | Edition 3 | Conveyancing | active |
Search and survey forms
What the third-party data providers return.
| Form | File | Version | Bounded context | Status |
|---|---|---|---|---|
| Local Authority Search | con29R.json | 2019 | Property Data Services | active |
| Drainage and Water Search | con29DW.json | current | Property Data Services | active |
| Leasehold Property Enquiries | lpe1.json | Edition 4 | Conveyancing | active |
| Freehold Management Enquiries | fme1.json | Edition 2 | Mortgage Lending | active |
| Local Land Charges Search | llc1.json | v2 | Property Data Services | active |
| Optional Enquiries of Local Authority | oc1.json | v21 | Property Data Services | active |
Specialist
Newer overlays covering domain-specific data.
| Form | File | Version | Bounded context | Status |
|---|---|---|---|---|
| Residential Development Survey | rds.json | v3.3.3 | Property Data Services | active |
| Sustainability Report 2024 | sr24.json | 2024 | Property Data Services | active |
Extension overlays (16)
Modular sub-pieces of NTS2 — opt into them individually on top of an NTS 2023 base. Each adds one specific feature so adopters can stage their migration from NTS → NTS2 without committing to the entire 2025 spec at once.
| Group | Key | Description | NTS2 ref |
|---|---|---|---|
| Specialist issues | as | Asbestos | A5.2 |
dr | Dry-rot treatment | A5.1 | |
jk | Japanese knotweed | A5.3 | |
sb | Subsidence / structural faults | A5.4 | |
hs | Health & safety issues | A5.5 | |
| Property features | oa | Outside areas (garden / balcony / communal) | — |
la | Loft access & insulation | A4.1 | |
sf | Spray-foam insulation | A4.2 | |
mc | Main construction type | — | |
| Ownership & financial | er | Estate rentcharges (freehold) | A3.2 |
ma | Managing agent (leasehold) | A1.5.4 | |
tf | Transfer fees | A3.5.1.1 | |
| Utilities & services | sl | Solar-panel ownership | B3.7.1 |
hi | Heating installation date | B3.4.3.2 | |
fd | Flood defences | — | |
| Transaction | oc | Other property chain dependency | — |
How an overlay is defined
Every overlay is a draft-07 JSON Schema with this skeletal shape:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://trust.propdata.org.uk/schemas/v3/overlays/baspi5.json",
"required": ["participants", "propertyPack"],
"properties": {
"propertyPack": {
"baspi5Ref": "B",
"required": ["priceInformation", "ownership", "..."],
"properties": {
"priceInformation": {
"baspi5Ref": "B.1",
"properties": { /* … */ }
}
}
}
}
}
The pieces that make an overlay an overlay:
- Form reference attributes —
baspi5Ref,ntsRef,nts2Ref,ta6Ref,ta7Ref,ta10Ref,lpe1Ref,fme1Ref,con29RRef,con29DWRef,rdsRef,piqRef. Each schema node carries the paper-form section number it traces back to. requiredarrays — fields the form mandates. Different overlays make different things required.title/descriptionannotations — form-specific wording (often different from the base or another overlay).oneOfdiscriminators — the canonical pattern is theyesNodiscriminator: whenyesNo= "Yes", adetailsfield becomes required.
How overlays are used at runtime
Composition happens via the library entrypoint
getTransactionSchema(schemaId, overlays[]) in index.js:
const { getTransactionSchema } = require('@pdtf/schemas');
// Estate-agency product:
const eaSchema = getTransactionSchema(
"https://trust.propdata.org.uk/schemas/v3/pdtf-transaction.json",
["baspi5", "nts2"]
);
// Conveyancer product:
const cnvSchema = getTransactionSchema(
"https://trust.propdata.org.uk/schemas/v3/pdtf-transaction.json",
["ta6", "ta7", "ta10", "lpe1"]
);
// Selective NTS → NTS2 migration:
const stagedSchema = getTransactionSchema(
"https://trust.propdata.org.uk/schemas/v3/pdtf-transaction.json",
["nts2023", "jk", "tf"] // NTS 2023 + Japanese knotweed + transfer fees
);
Under the hood, the merge pipeline is:
base transaction schema]:::src O1[Overlay 1
e.g. baspi5]:::src O2[Overlay 2
e.g. nts2]:::src O3[Overlay n …]:::src MERGE["deepmerge( base, O1, O2, … )
+ custom arrayMerge for
required & oneOf"]:::proc RESULT[Merged schema
complete and validatable]:::out BASE --> MERGE O1 --> MERGE O2 --> MERGE O3 --> MERGE MERGE --> RESULT
deepmerge with a custom arrayMerge: required arrays are unioned, oneOf arrays are concatenated, and the rest follows ordinary object-merge rules.
Names and aliases
Overlays are registered in overlaysMap[schemaId] in index.js under versioned aliases as well as the plain filename stem. Both work:
Alias in overlaysMap | File |
|---|---|
baspiV4 | baspi4.json |
baspiV5 | baspi5.json |
ta6ed4 | ta6.json |
ta7ed3 | ta7.json |
ta10ed3 | ta10.json |
lpe1ed4 | lpe1.json |
fme1ed2 | fme1.json |
llc1v2 | llc1.json |
nts2023 | nts.json |
ntsl2023 | ntsl.json |
nts2025 | nts2.json |
ntsl2025 | ntsl2.json |
con29R2019 | con29R.json |
con29DW | con29DW.json |
rdsV333 | rds.json |
oc1v21 | oc1.json |
piqV3 | piq.json |
sr24 | sr24.json |
Bounded-context map
Each overlay belongs to exactly one bounded context:
| Bounded context | Main overlays |
|---|---|
| Estate Agency | baspi4 (legacy) · baspi5 · nts (legacy) · nts2 · ntsl (legacy) · ntsl2 |
| Conveyancing | ta6 · ta7 · ta10 · lpe1 |
| Mortgage Lending | fme1 |
| Surveying | piq |
| Property Data Services | rds · oc1 · llc1 · con29R · con29DW · sr24 |
| Property Tech | The base pdtf-transaction.json + verified-claims wrapper (no overlays of its own) |
The extension overlays (jk, tf, …) are all sub-pieces
of NTS2, so they belong to Estate Agency.
Where this lives
- Overlay JSON files:
source/03-standards/schemas/src/schemas/v3/overlays/ - Extension overlays:
source/03-standards/schemas/src/schemas/v3/overlays/extensions/ - Upstream README:
source/03-standards/schemas/src/schemas/v3/overlays/README.md - Merge entrypoint:
source/03-standards/schemas/index.js(functiongetTransactionSchemaat line 170) - Bounded-context mapping rationale: Bounded contexts (DDD)