Thank you for your interest in the Zoopla Property Group (ZPG) Real-time Listings Service.
To achieve this, data about available properties needs to be transferred from estate agents' software systems to ZPG. Traditionally the data transfer involves exporting large volumes of data from a database, providing a comprehensive picture of the estate agent's properties at that time. This method has the benefit of being very easy to implement but it is also very slow (due to the amount of data involved) and inefficient (most of that data has not changed since the previous export). These limitations mean that it is usually only performed once a day, overnight.
The level of service that users and estate agents now expect means that the daily bulk transfer of data is no longer suitable; the ZPG Real-time Listings Service is its replacement. It allows estate agents to make changes on their system and have those changes reflected on ZPG's websites within minutes. It achieves this by reducing the amount of data that needs to be transferred: only information about listings which have actually changed needs to be transmitted (i.e. updates are incremental).
What follows is the technical specification of the ZPG Real-time Listings Service so that anyone who wishes to integrate it with their systems may do so.
The ZPG Real-time Listings Service is designed to interact with a central data provider. Estate agents manage their properties using either a cloud-based property management solution or locally installed software which logs changes to a central data system. As changes are registered on this central system it sends messages to the ZPG Real-time Listings Service, in order to update ZPG's version of that data, which is displayed on its websites.
The ZPG Real-time Listings Service uses a fairly conventional web service design. Clients communicate with the service using standard HTTP over a secure connection (HTTPS). Each method (action) that the service provides has its own dedicated URL. The data required for the method is sent in a JSON formatted message.
The service runs in two environments: sandbox and live. The sandbox environment is used for testing your system's messaging interactions; whilst the live environment is for data you intend to be published to our websites. Initially we will provide you with access to the sandbox environment and once you are happy with your implementation you will be granted access to the live environment.
There are two principal entities which are tracked: branches and listings. A branch can have many listings associated with it but a listing can only belong to one branch. Whenever a change to a branch or listing is registered by your system, its full details should be sent to us. We will then replace our record entirely with your new version.
The media content for a listing (e.g.: images; brochures) is not transferred directly via the service. Instead, the content should be hosted on a web server and associated URLs included in a listing/update message. We will then download that content from your web server.
For a more detailed description of this workflow please see Workflow overview.
How you generate a public-private key-pair and associated certificate signing request will be dependent on your particular software platform. For reference, this is how you might do it on Linux using openssl:
1. Create the public-private key-pair.
openssl genrsa -out private.pem 2048
This generates a key-pair using the RSA algorithm with keys that are 2048 bits long, which is then output to the file private.pem. Note that this file includes everything about the generated key-pair and the public key can be produced from the information it contains. Reminder: private.pem should never leave your corporate network.
We suggest that when you create your key-pair you do not specify an accompanying password. Otherwise you'll have to provide that password (to decrypt the file) every time your system is restarted. The lack of a password will not affect the security of the connection itself. The example given here does not set a password.
If you are interested, you can look at the contents of private.pem:
openssl rsa -in private.pem -text
2. Create a certificate signing request.
openssl req -new -sha256 -key private.pem -out public.csr
The certificate signing request is output to file public.csr and is the file you would submit to our certificate signing request submission page.
If you are interested, you can look at the contents of public.csr:
openssl req -in public.csr -text
How you configure your system to use the private key and signed certificate to establish an HTTPS connection will be dependent on your particular software platform. Consequently our ability to advise you on how to troubleshoot authentication issues is limited. However, if you use Linux you can test that the private key and signed certificate work together correctly by:
echo '{"branch_reference":"test"}' | curl --key /path/to/private.pem --cert /path/to/certificate.crt --data @- --header "Content-type: application/json; profile=http://realtime-listings.webservices.zpg.co.uk/docs/v2.0/schemas/listing/list.json" https://realtime-listings-api.webservices.zpg.co.uk/sandbox/v2/listing/list
which should receive the following response:
{
"status": "OK",
"listings": [],
"branch_reference": "test"
}
You can test send any of the message examples in a similar way, although you may need to include additional headers (see 4. Messaging).
The ZPG Real-time Listings Service only accepts secure connections using the TLS 1.2 protocol.
Since security is so important it is worth explaining why this is the case. As previously discussed, security is composed of two parts: identity and privacy. Whilst the data being sent to the Real-time Listings Service is not particularly sensitive (privacy), being assured that the person sending the data is actually who they claim to be (identity) is paramount: no-one should be able to read/change data except its legitimate owner.
(ZPG also expects to launch other services in future. Those services may be dealing with data that is sensitive and should therefore be transmitted in a suitable manner. The Real-time Listings Service is the first of these services, and so we have taken the opportunity to establish best practice standards at the outset, so that partners are familiarised with our security requirements, leading to fewer suprises or problems in future.)
There are a number of industry-standard secure communication protocols - many of which have become obsolete due to flaws in their design :
After reviewing library support for TLS across programming languages and operating systems, we determined that, in the vast majority of cases, if TLS 1.1 was supported then TLS 1.2 was too. We therefore feel comfortable that by restricting access to TLS 1.2 we are following best practice guidelines, should not cause undue disruption, and is in the interest of all users of our services.
(Note that in JSON nomenclature an object's attributes are called "properties", which is somewhat unfortunate given the industry we operate in. In order to remove any possibility of ambiguity, this documentation refers to "attributes" instead and the only use of the word "properties" in our schemas is as required by the JSON standard, not as the name of a data attribute.)
The JSON message would then be sent to the method's URL endpoint using an HTTP POST. Having received your message the service will respond with a standard HTTP response status code and provide additional information in the response content, formatted in JSON.
The ZPG Real-time Listings Service operates in two environments:
sandbox, for testing:https://realtime-listings-api.webservices.zpg.co.uk/sandbox/v2/
live, for data destined for our websites:https://realtime-listings-api.webservices.zpg.co.uk/live/v2/
Having chosen the correct environment, you then append the name of the method you wish to call. For example:
You would then use an HTTP POST to send your JSON message to that endpoint, along with the appropriate HTTP headers.
Reminder: your software will need to have been configured so that it can access both the signed certificate and private key, discussed in 3. Security and authentication, when you contact either of these environments. This is so that the secure HTTPS connection can be established.
Please note that the endpoints reference the major component of the API version number you wish to use, whilst the JSON schemas also include minor version components, which must be specified in the Content-Type profile.
(You will initially be given access to the sandbox environment to test your system integration. Data sent here will not affect ZPG's websites. When you are happy that your system integration is complete, you will need to contact us to gain access to the live environment. At that time we will then discuss the best way to perform an initial upload of all your branch and listing data, as well as how to migrate any existing clients who currently use an FTP feed.)
Note that some schema versions may not be available in the live environment; for example, during the development and testing of new versions, or because an old version has been retired. Please refer to our current message schemas to see which environments support the API version documented here.
The JSON message should be sent to the URL endpoint for the method you wish to use, via a POST.
The Content-Type should be set to application/json, along with a profile definition, which is the URL of the specific version of the message schema you are conforming to. e.g.:
Content-Type: application/json; profile=https://realtime-listings.webservices.zpg.co.uk/docs/v2.3/schemas/listing/update.json
ZPG-Listing-ETag is the mechanism for ensuring that the listings on your system and ours are synchronised. Whenever you send us a listing/update message we will replace the data we have with the new version. At a later date you may wish to check whether the data we have is indeed the same as yours. Rather than sending the entire message back to you - which would then require you to compare all the individual attributes to find differences - we instead ask that you provide us with metadata that will allow your system to quickly determine whether the listing data we have is synchronised with yours. This metadata is sent via the ZPG-Listing-ETag header with each listing/update message, which can later be retrieved via the listing/list method.
The ZPG-Listing-ETag value is a string that you define (up to 255 characters in length) that indicates the overall state of the listing, as represented by the listing/update message. Its value should:
i.e. if something changes on your system that would change the listing/update message you would send to us, then the accompanying ZPG-Listing-ETag should change to reflect that.
We recommend using a checksum of the canonicalised listing/update message. Depending on how your system tracks changes to listing data (and how it is sent to us) an auto-incrementing revision_id, or a last-modified date may also be suitable.
The ZPG-Listing-ETag you provide will be returned by the listing/list method. By comparing its value with the one your system would produce now, you can determine whether it is necessary to refresh the listing on our system. Please see 10.3 Periodically check synchronisation for additional information about this process.
The service supports the following methods:
Please see the current message schemas and example messages for each method.
This method allows you to describe a listing. It is used for both creation and update purposes and, in either case, the listing should be described in its entirety.
There are a small number of mandatory attributes:
The remaining attributes are all optional according to our schema and specification, however some are strongly advised, where they relate to material information required as published in guidance by the National Trading Standards Estate and Letting Agency Team (NTSELAT). All the additional information you can provide improves our ability to successfully match the listing to a user's search. If you do not have any data for a particular attribute, then do not include it in your message - do not default it. This will make it less likely for the message to fail validation rules which use the attribute and you won't accidentally introduce meaning (and consequence) where there was none before.
There are three attributes which define how we will interpret the listings's data:
Attributes which are nonsensical when considered in the above context will be ignored (for example: council_tax_band will be ignored if the location:country_code indicates an overseas (non-UK) listing).
Message attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
accessibility | array of enum | Whether the property includes accessibility features for disabled people. Where a particular option is not appropriate, we advise that the accessibility improvements be described in more detail via feature_list or detailed_description. | lateral_living, step_free_access, wheelchair_accessible, wet_room, disabled_features, level_access, ramped_access, lift_access, stair_lift, wide_doorways, level_access_shower, variable_height_kitchen_surfaces | |
administration_fees | string | A description of the estate agent's administration fees. | "£10 per person." | |
annual_business_rates | number | The annual business rate (UK national non-domestic tax rate) applicable to this property. | 150.00 | |
areas | Best practice (commercial); Mandatory (when providing EITHER pricing:price_per_unit_area OR price_qualifier="non_quoting") | areas object | The internal/external areas of the property. | |
available_bedrooms | integer | The number of vacant bedrooms being offered in shared accommodation. Note that if supplying this attribute, shared_accommodation must be present and true, although the relationship is asymmetric. See shared_accommodation for more details. | 2 | |
available_from_date | Best practice (rent) | datetime | The earliest date that a property can be moved into by the new owner/tenant. | "2010-01-31"; "2010-01-31T12:00:00" |
basement | boolean | Whether the property has a basement/cellar. | true | |
bathrooms | Best practice (residential) | integer | The number of bathrooms (or shower rooms) within the property. | 1; 3 |
bills_included | array of enum | Which utility bills are included in the rental price. | "electricity", "gas", "internet", "satellite_cable_tv", "telephone", "tv_licence", "water", | |
branch_reference | Mandatory | string | Your unique identifier for the branch, previously sent via branch/update:branch_reference. | "1234"; "kd-789d" |
broadband_supply | array of enum | An accurate information as to the nature of the supply (or supplies) of internet broadband to the property | "adsl", "cable" Click for full list | |
building_safety_issues | array of strings | An accurate description of any known building safety issues as well as any planned or required works needed to rectify any identified defect/hazard | "Unsafe cladding", "Lack of emergency lighting where required" | |
burglar_alarm | boolean | Whether the property has a burglar alarm installed. | true | |
business_for_sale | boolean | Whether the business currently operating at the premises is included as part of the sale. | true | |
buyer_incentives | array of enum | The list of applicable incentive schemes available to the buyer of the property. | "equity_loan", "help_to_buy", "mi_new_home", "new_buy", "part_buy_part_rent", "shared_equity", "own_new_rate_reducer", "deposit_unlock", "part_exchange" | |
category | Mandatory | enum | Whether the property is commercial or residential. | "commercial", "residential" |
central_heating | enum | The extent to which a property has central heating. | "full", "partial", "none" | |
chain_free | boolean | Whether the sale of the property is unencumbered by the current owner needing to purchase another property. | true | |
commercial_use_classes | array of strings | The commercial use classes for which the property is currently approved. | ["A3", "D2"] | |
connected_utilities | array of enum | A list of utilities which are connected to the property. | "electricity", "fibre_optic", "gas", "satellite_cable_tv", "telephone", "water" | |
conservatory | boolean | Whether the property has a conservatory. | true | |
construction_year | integer | The year the property was constructed. | 2010; 1701 | |
construction_materials | no, but cannot be an empty list | array of strings | a list of notable materials involved in the building's construction | "brick", "concrete", "thatched roof" |
content | Best practice | array of content objects | A list of media content associated with the listing. (These will be displayed in the order provided.) | |
decorative_condition | enum | An indication of the general decorative state of the property. | "excellent", "good", "average", "needs_modernisation" | |
deposit | number | The tenancy deposit amount. (This should be in the same currency as pricing:currency_code.) | 500.00 | |
detailed_description | Mandatory | array of description objects | The detailed description of the property. Please see 8. Structuring of detailed descriptions for additional information, including examples of usage. | |
display_address | string | The address string to be displayed on the website. Please note that the display of this string is subject to our data validation and presentation rules . It must be formatted with minimum of 1 comma and minimum of 2 addressing entities. For Example: "street_name, locality, town_or_city" OR “street_name, town_or_city” | "Barker Road, Sutton Coldfield, Birmingham" | |
double_glazing | boolean | Whether the property has double glazed windows. | true | |
electricity_supply | array of enum | An accurate description or statement as to the nature of the supply (or supplies) of electricity to the property - may be more than one. | "mains_supply","private_supply", "solar_pv_panels", "wind_turbine","generator","other" | |
epc_ratings | epc_ratings object | The Energy Performance Certificate (EPC) ratings. | ||
feature_list | array of string | A list of important aspects about the property the agent wishes to highlight; "bullet points". Please see 8. Structuring of detailed descriptions for more information about how these are displayed. | ["Newly carpeted throughout", "Remodelled kitchen"] | |
fireplace | boolean | Whether the property has a room with a fireplace. | true | |
fishing_rights | boolean | Whether ownership of the property also grants the owner the right to fish in waters that cross the property's borders. | true | |
floor_levels | array of enum | Which floors the property occupies in a multi-storey building. Please see our floor labelling convention. | ["ground", 1] Click for more | |
floors | integer | The total number of floors that the property occupies. | 2 | |
furnished_state | Best practice (residential rent) | enum | The amount of furnishing provided by the landlord. | "furnished", "furnished_or_unfurnished", "part_furnished", "unfurnished" |
google_street_view | google_street_view object | Position and orientation for Google Street View. | ||
ground_rent | ground_rent object | Information about the ground rent payments and their related rate increases | 100.00 | |
gym | boolean | Whether the property has access to a private or communal gym. | true | |
heating_source | array of enum | An accurate description or statement as to the nature of the supply/supplies of heating at the property | "biomass_boiler", "electric_mains", "gas_mains" Click for full list | |
known_planning_considerations | no, but cannot be an empty string | string | Information about any known or in progress planning permissions, requirements both at and around the property | "article 4 (or related) directions from the local authority apply to this property" "neighbor is building and extension that may impact on privacy or light" |
letting_arrangements | Best practice (residential rent, where applicable). Holding deposit | string | If a residential rental listing will not confer a residential tenancy which the average consumer would expect to obtain (e.g. an assured shorthold tenancy in England), the alternate letting arrangements should be described here. If a holding deposit is required, this must be clearly stated on the listing. You must comply with any specific requirements in the devolved nations that apply in respect of the holding deposit amount, e.g. Tenant Fees Act 2019 in England and the Renting Homes (Fees etc.) (Wales) Act 2019 in Wales. | Non-assured shorthold tenancy "1000" |
life_cycle_status | Mandatory | enum | An indication as to where the listing is in its life cycle, from initial availability, through offers being made, to its legal conclusion. For rent: available -> under_offer -> let_agreed -> let. For sale: available -> under_offer -> sold_subject_to_contract -> sold. | "available", "under_offer", "sold_subject_to_contract", "sold", "let_agreed", "let", |
listed_building_grade | enum | The grade assigned to the property should it be listed as a building of special architectural or historic interest. | "category_a", "category_b", "category_c", "grade_a", "grade_b", "grade_b_plus", "grade_one", "grade_two", "grade_two_star", "locally_listed" | |
listing_reference | Mandatory | string | Your unique identifier for the listing. This should be unique across your entire system, not just for its associated branch (i.e. this is the PRIMARY KEY). If your identifiers are based on those submitted by the agent themselves then you may wish to concatenate, with an unambiguous separator, your branch reference and their listing reference to ensure uniqueness (e.g. "branch_id|agent_listing_id"). | "5678"; "dfhd-kjdf-1" |
living_rooms | Best practice (residential) | integer | The number of living rooms within the property. | 1 |
local_authority | Best practice (residential) | local_authority object | Information about charges issuable by a local authority. | |
location | Mandatory | location object | Information about the location of the property, such as its address. | |
loft | boolean | Whether the property has a loft/attic. | true | |
new_home | boolean | Whether the property is newly built and has had no previous occupants. | true | |
open_day | datetime | The date of the next open-to-all viewing of the property. | "2010-01-31" | |
outbuildings | boolean | Whether the property has additional outbuildings, such as stables or a greenhouse. | true | |
outside_space | array of enum | What outside areas are available. | "balcony", "communal_garden", "private_garden", "roof_terrace", "terrace" | |
parking | array of enum | What parking facilities are available. | "double_garage", "off_street_parking", "residents_parking", "single_garage", "underground" Click for full list | |
pets_allowed | boolean | Whether the landlord accepts tenants who have pets. | true | |
porter_security | boolean | Whether the property resides in a complex or building which has an on-site porter/attendant. | true | |
pricing | Mandatory | pricing object | Information about how the listing is priced. | |
property_type | Mandatory | enum or string | The broad architectural type of the property. Please note that a particular property_type is only valid within certain contexts. | "maisonette" Click for more |
rateable_value | number | The estimated open market annual rental value of the premises (in GBP). | 15000.00 | |
rental_term | minimum_contract_length object or enum | An indication of the duration of the rental contract. | "fixed_term", "long_term", "short_term" | |
repossession | boolean | Whether the sale is for a repossessed property. | true | |
retirement | boolean | Whether the property is for retirees-only. | true | |
restrictions | restrictions object | attributes or information relating to restrictions on or around this property | ||
rights_and_easements | rights_and_easements object | attributes or information relating to easements on or around this property | ||
risks | risks object | An accurate description or statement as to any known risk of, or actual damage to the property. | ||
sap_rating | integer | The SAP rating for this property. | 85 | |
service_charge | service_charge object | The service charge applicable to the property. | ||
serviced | boolean | Whether the premises are serviced. | true | |
sewerage_supply | array of enum | An accurate description or statement as to the nature of the sewerage arrangements at the property. | "mains" Click for full list | |
shared_accommodation | boolean | Whether the listing is for shared accommodation (i.e. the listing is for a room, or rooms, within an existing house/flatshare). If this attribute is true, we recommend also supplying the available_bedrooms attribute. | true | |
summary_description | string | A brief summary of the property. This is displayed in search results and recommend that it is limited to 255 characters. | "A well decorated house with lots of space with easy access to nearby shops and public transportation." | |
swimming_pool | boolean | Whether the property has a swimming pool. | true | |
tenanted | boolean | Whether the property being sold is currently occupied by renting tenants. | true | |
tenant_eligibility | tenant_eligibility object | The eligibility of potential tenant classes that can apply (e.g. students only). | ||
tennis_court | boolean | Whether the property has a tennis court. | true | |
tenure | tenure object | The tenure of the property. | ||
total_bedrooms | Best practice (residential) | integer | The total number of bedrooms within the property. When describing shared accommodation, see also available_bedrooms. | 3 |
utility_room | boolean | Whether the property has a utility room. | true | |
waterfront | boolean | Whether the property is close by to a large body of water such as the sea, a lake or river. | true | |
water_supply | array of enum | An accurate description or statement as to the nature of the supply of water to the property | "mains", "private_well" Click for more | |
wood_floors | boolean | Whether the property has rooms with exposed wooden floors. | true |
This method allows you to describe a branch, to which listings are then associated. The address and other contact details allow us to identify the equivalent branch on our system and map your branch_reference to ours.
Note that this method is optional. If you do not use it then the branch information will need to be transferred to ZPG in some other way (typically via an emailed CSV spreadsheet), although this will likely delay the integration of branches with our system.
Message attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
branch_reference | Mandatory | string | Your unique identifier for the branch. (We do not generally issue these as it should be the identifier that is native to your system. This makes debugging easier for you and means you do not need to wait for any additional information from us before you can start uploading listing data for a branch.) | "1234"; "kd-789d" |
branch_name | Mandatory | string | The name of the branch. This is usually the name of the company and may also include some location information in order to differentiate it from other branches in the company. | "Estate Agent Ltd - Shepherd's Bush" |
location | Mandatory | location object | Information about the location of the branch, such as its address. | |
telephone | string | Telephone number. | "02079460184"; "+1 246-123-4567" | |
string | Email address. | "[email protected]" | ||
website | string | The URI-encoded URL for the branch's website, or that of its parent company if it doesn't have one of its own. | "http://www.estateagentltd.co.uk" |
This method allows you to remove a listing from a branch's inventory list.
Message attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
listing_reference | Mandatory | string | Your unique identifier for the listing that you wish to remove, previously sent via listing/update:listing_reference. | "1234"; "kd-789d" |
deletion_reason | enum | Why the listing is being deleted. | "withdrawn", "offer_accepted", "exchanged", "completed", "let" |
Because of the incremental nature of the service it is possible for the data that ZPG has to drift relative to yours (because of network problems or uncaught errors, for example). It is recommended that you periodically check the synchronisation of data between our system and yours. The listing/list method allows you retrieve a summary of the listing inventory for a branch and their state.
Message attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
branch_reference | Mandatory | string | Your unique identifier for the branch, previously sent via listing/update:branch_reference. | "1234"; "kd-789d" |
The response will include the listing inventory for the branch as an array of:
Response attribute | Type | Description | Example |
---|---|---|---|
listing_reference | string | Your unique identifier for the listing, previously sent via listing/update:listing_reference. | "1234"; "kd-789d" |
listing_etag | string | This is the string that you specified in the ZPG-Listing-ETag HTTP header when you last called listing/update, referring to listing_reference. If the value is not the same as the one you expect then there is a synchronisation issue and you should call listing/update again to refresh the data that ZPG has. | "18ab1f2e4c8ed62882fa57380c9b7b026413a663" |
url | string | A link to the listing's detail page. (When using the sandbox environment this links to a preview page; when using the live environment it is a redirect to the detail page on Zoopla's website.) |
Please see 10. Workflow overview for additional information about how to use this method.
If you include an attribute in your method call that uses an object to represent it, a valid object must be supplied. When discussing objects, a constituent attribute described as being mandatory is with reference to how to produce a valid object; it does not imply that the object, nor the attribute that uses that object, is mandatory when calling a particular method. Please refer to the method itself to see whether a particular attribute is mandatory.
This describes a single area. It is a constituent of a number of other objects. This should not be confused with the areas object.
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
value | Mandatory | number | The area value. | 54.5 |
units | Mandatory | enum | The units of measurement used. | sq_feet, sq_yards, sq_metres, acres, hectares |
The internal/external areas of the property.
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
external | min_max_area object | The external area of the property. | ||
internal | Mandatory (when specifying pricing:price_per_unit_area) | min_max_area object | The internal area of the property. |
A content object specifies a single piece of media content associated with the listing, such as an image or brochure. The listing/update:content attribute is an array of these content objects, which will be displayed in the order provided. Please see 9. Retrieval of media content for more information about how the content will be retrieved from the specified URLs.
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
url | Mandatory | string | The URI-encoded URL for the media content to download. | "http://www.estateagentltd.co.uk/properties/images/1234.jpg" |
type | Mandatory | enum | The content type. | "audio_tour,brochure,document,epc_graph,epc_report,floor_plan,home_pack,image,site_plan,virtual_tour |
caption | string | A short description of the content. This will be displayed alongside the content or, where appropriate, used as the hyperlink text. | "The entrance hall." |
This object describes the geographic location of a point on the Earth's surface using the latitude/longitude system. We recommend you store latitude/longitude with a precision of at least 5 decimal places, which allows for locating a point to within approximately 1 metre.
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
latitude | Mandatory | number | The latitude, measured in degrees, of the property. | -90.000000; 54.123456; 90.000000 |
longitude | Mandatory | number | The longitude, measured in degrees, of the property. | -180.000000; 119.265984; 180.000000 |
The description is expressed as an array of description objects, each of which represent a paragraph or section. For additional information about how to use this object, including examples, please see section 8. Structuring of detailed descriptions.
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
heading | See below | string | The title of the section. | "Kitchen" |
dimensions | dimensions object or string | The dimensions of the room, when the section is describing a individual room. (The dimensions object is the preferred and recommended representation because the string variant is subject to our data validation and presentation rules and so may not be displayed.) | ||
text | See below | string | The main text for this section. |
Requirements: you must provide at least one of heading or text per object, whilst dimensions is optional (but contingent on the presence of a heading).
Information about the dimensions of a room.
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
length | Mandatory | number | The length of the room. | 12 |
width | Mandatory | number | The width of the room. | 10 |
units | Mandatory | enum | The units of measurement used. | feet,metres |
This will be displayed as "length x width" with appropriate unit markers. Traditionally, length is greater than width, but this is not required.
The Energy Performance Certificate (EPC) provides information about the energy efficiency and environmental impact of the property.
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
eer_current_rating | integer | The current Energy Efficiency Rating (EER). | 80 | |
eer_potential_rating | integer | The potential Energy Efficiency Rating (EER). | 95 | |
eir_current_rating | integer | The current Environmental Impact (CO2) Rating (EIR). | 50 | |
eir_potential_rating | integer | The potential Environmental Impact (CO2) Rating (EIR). | 100 |
Disaster Risks - accurate information as to any known risk of, or actual damage to the property, if a risk is present then it's attribute cannot be empty or null. at least 1 risk mush be provided and cannot be null/empty
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
flooding_risks | flooding_risks object | details regarding any risks related to flooding which affect the property | ||
coastal_erosion_risk | boolean | are there any coastal erosion risks which affect the property | false | |
mining_risks | mining_risks object | details regarding any risks related to mining activity which affect the property |
Flooding Risk - provides users with relevent information around risk of flooding at the property. if configured cannot be empty
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
flooded_within_last_5_years | boolean | Has the property has experienced a flood event within the past 5 years | false | |
sources_of_flooding | Mandatory, but only if flooded_within_last_5_years is true | array of enum | list of sources of any exposure to flooding | [ "river", "lake" ] Click for full list |
flood_defenses_present | Mandatory, but only if flooded_within_last_5_years is true | boolean | declare whether there are any flood defences at the property | true |
Mining Risk - prvoides infomation where a property is known to be on the coalfield or directly impacted by the effect of other mining activity. if configured cannot be empty
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
coalfields | boolean | Is the property on a coalfield | false | |
other_mining_activities | boolean | are there any other mining related activities which may affect this property | true |
Google Street View provides users with the ability to virtually explore outdoor areas. This is becoming increasingly valuable to users, who are able to, for example: plan routes to bus stops; see which services are provided by local shops.
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
coordinates | Mandatory | coordinates object | The coordinates of the point where StreetView should be initially located. | |
heading | Mandatory | number | The angle of rotation to the right of the view, measured in degrees, relative to north. Also known as compass heading, or bearing. | 0 (north); 74.5; 90 (east); 360 (north) |
pitch | Mandatory | number | The angle of rotation up/down of the view, measured in degrees, relative to the horizon. | -90 (straight down); 5.4; 90 (straight up) |
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
amount | Mandatory | number | The annual amount payable. This value will be considered to be in the same currency as pricing:currency_code. | 1100 |
The following fields are optional
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
review_period | number | The number of years between reviews of the ground rent amount. | 2 | |
date_of_next_review | string | The date that the ground rent is next due to be reviewed, particularly for when review_period is greater than 1 year. Note that this is a date-like string whose validation is not as restrictive as the datetime used for other attributes. It may be any of the following formats: YYYY-MM-DD; YYYY-MM; YYYY. | "2026-01-31"; "2026-01"; "2026" |
council_tax_band represents one of a set of submittable values. Either the band itself as a simple string, or one of two objects representing that the property is exempt, or that the band is unknown at this point in time. The latter is most likely used for newbuild properties where bands have not yet been decided. Either exemption or unknown status must also provide a reason as part of the submission.
Please note that Council Tax (UK) is considered material information and must be included in the listing. In very limited circumstances, listings may be exempt from council tax. If that is the case, a reason for the exemption must be provided within the listing description as per below.
Either a simple string such as: "A" or an object containing one of the following two keys: "B", "C", "D", "E", "F", "G", "H", "I"
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
exempt | mandatory reason to be provided if declared | string | The property itself is exempt from the payment of council tax for the given reason. | "Student hall of residence" |
not_yet_known | mandatory reason to be provided if declared | string | The band is unknown at this point in time for the reason provided. | "A band has not been assigned to this new subdivision yet." |
domestic_rates represents one of a set of submittable values. Either a number value Northern Ireland domestic rates annual payable value. Either the rate itself as a number (taken as per annum), or one of two objects representing that the property is exempt from paying rates, or that the rate is unknown at this point in time. Either exemption or unknown status must also provide a reason as part of the submission.
Either a simple non-zero number such as: "100" or an object containing one of the following two keys:
Please note that Domestic Rates (NI) is considered material information and must be included in the listing. In very limited circumstances, listings may be exempt from council tax. If that is the case, a reason for the exemption must be provided within the listing description.
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
exempt | mandatory reason to be provided if declared | string | This should only be used where the property itself is exempt from the payment of domestic rates for the explicit legalreasons. | "Student hall of residence" |
not_yet_known | mandatory reason to be provided if declared | string | The domestic rates are non yet known at this point in time for the reason provided. | "rates have not been assigned to this new subdivision yet." |
Charges issuable by a local authority. One of the following keys must be specified if the local_authority key is submitted.
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
council_tax_band | council_tax_band object | British council tax details | ||
domestic_rates | domestic_rates object | Northern Ireland domestic rates annual payable details. | 730 |
Providing an accurate address and location for the property is incredibly important because a large number of existing and future features on our websites depend on it. For example: which council is responsible for the maintaining and taxing the local area; or average travel times between the property and other locations of interest to the user.
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
property_number_or_name | Best practice; mandatory when not providing street_name. | string | The public designation of the property. | 15; "14A"; "Flat B, 41"; "The Wildings" |
street_name | Best practice; mandatory when not providing property_number_or_name. | string | The name of the road on which the property is principally adjacent. | "Barker Road"; "Chestnut Street" |
locality | string | The familiar name of the area as it is referred to by local residents. This is usually a traditional, historic name and may refer to an aspect of the area which has ceased to exist. | "Sutton Coldfield"; "North Beach" | |
town_or_city | Mandatory | string | The nearest large urban area to the property. This is usually included in the property's postal address and sometimes referred to as "post town". Note that this does not imply that the property resides within the boundaries of this urban area (for example, it might be in an outlying village - which would be referenced via the locality). | "Birmingham"; "San Francisco" |
county | string | The largest territorial area division within the country which the property resides in. (Synonymous with e.g.: province; principality.) | "West Midlands"; "California" | |
postal_code | Mandatory (UK) | string | The postal area code issued by the primary postal service in the country. For example, for the UK, this would be Royal Mail's postcode; for the US, the United States Postal Service's ZIP code. | "B19 4JY"; "94112" |
country_code | Mandatory | string | The ISO 3166-2(preferred) orISO 3166-1 alpha-2country code. Listings for properties in Guernsey, Jersey and the Isle of Man should use the 'GB' country code. | "GB-BIR"; "US" |
coordinates | Best practice | coordinates object | The geographic location of the property. | |
paf_address | paf_address object | Royal Mail's address reference. | ||
paf_udprn | string | Royal Mail's Unique Delivery Point Reference Number (UDPRN). | "00001234" | |
uprn | string | The Unique Property Reference Number (UPRN) is a unique identifier assigned to each addressable property in the United Kingdom (UPRN). is a unique number up to 12 characters in length | "1234", "00001234 |
Note that there is a hierarchical order to the address attributes, so in order of increasing size:
If your software does not currently support the separation of the property_number_or_name from street_name (i.e. they are stored as a single string value; for example: "29 Acacia Road"), then please supply that string via street_name.
The rental_term attribute can be specified with a minimum_contract_length object or, if the contract length is not currently known, by an enum that roughly indicates its likely duration (e.g. "short_term").
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
minimum_length | Mandatory | number | The minimum duration of the contract. | 6 |
units | Mandatory | enum | The units of measurement used. | days,weeks,months,years |
The min_max_area object defines an area range. Where only one is specified, we will regard them both as having the same value - i.e. a fixed area.
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
minimum | area object | The minimum area. | ||
maximum | area object | The maximum area. |
supporting information pertaining to any known statutory/contractual restrictions or obligations that relate, restrict or require the use of land, restrictions on resale and/or require it to us used, maintained or preserved is a certain manner. If provided cannot be empty or null
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
conservation_area | boolean | do any restrictions apply due to the property being in a conservation area | ||
lease_restrictions | boolean | are there any restrictions in the lease (provide details in the listing description if yes) | true | |
listed_building | boolean | do any restrictions apply due to the property having a listed building status | true | |
permitted_development | boolean | are there any restrictions on what kind of property development is permitted | false | |
real_burdens | boolean | Applies in Scotland only. Does a real burden apply to this property. This is normally an obligation affecting land or buildings. | false | |
holiday_home_rental | boolean | are there any holiday home rental restrictions on this property | false | |
restrictive_covenant | boolean | are there any restrictive covenants which apply to this property | false | |
business_from_property | boolean | are there any restrictions on running a business from this property | false | |
property_subletting | boolean | are there any terms or restrictions regarding subletting this property | ||
tree_preservation_order | boolean | are there any tree preservation orders related to this property | false | |
other | boolean | are there any other or additional restrictions not mentioned above. Please put details in the listing description | false |
supporting information pertaining to any known (or in progress) easements or rights that relate to the use of land, resale and/or require it to us used, maintained or preserved is a certain manner. If provided cannot be empty or null ained or preserved is a certain manner. If provided cannot be empty or null
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
right_of_way_public | boolean | are there any public rights of way (footpath, byway etc...) that relate to this property | true | |
right_of_way_private | boolean | are there any private rights of way (footpath, byway etc...) that relate to this property | true | |
registered_easements_hmlr | boolean | are there any registered (or in the process of registering) easements/rights with the hmlr (land registry) | true | |
servitudes | boolean | Normally only applies in Scotland. Are there any servitudes that affect this property | true | |
shared_driveway | boolean | is there a driveway shared with a different property | true | |
loft_access | boolean | does the property have to grant loft access to occupants of properties below, or have the right to access the loft via a property above (e.g. to maintain a water tank) | true | |
drain_access | boolean | does the property have to grant access to the land for the maintenance of drains | true | |
other | boolean | are there any other easements or rights associated with this property not otherwise given above. Please put details in the listing description | true |
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
address_key | Mandatory | string | The 8-digit Address Key. | "02341509" |
organisation_key | Mandatory | string | The 8-digit Organisation Key. | "00000000"; "00001150" |
postcode_type | Mandatory | enum | The Postcode Type. | "L"; "S" |
Note that Royal Mail's UDPRN (see location:paf_udprn) is generally preferred to paf_address because it is more stable with respect to changes in property utilisation (e.g. commercial becoming residential).
This object describes a price which is provided as a function of floor area.
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
price | Mandatory | number | The per unit area price. | 100.00 |
units | Mandatory | enum | The units of measurement used. | sq_feet, sq_yards, sq_metres, acres, hectares |
The pricing object's structure is determined by whether its component attribute transaction_type indicates that the listing is for sale or rent. Please note that we do not currently support multiple pricing, nor multiple transaction_types, for a single listing. If you do have multiple pricing models, perhaps due to a range of incentive schemes being available, then you should supply the non-subsidised price in the pricing object and indicate available incentive plans via listing/update:buyer_incentives.
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
transaction_type | Mandatory | enum | The type of financial transaction for this listing. | rent,sale |
currency_code | Mandatory | string | The ISO 4217 currency code for the stated price. Other monetary attributes (e.g. deposit) also use this as their currency. | "GBP"; "JPY" |
price | Mandatory (residential) | number | The non-subsidised price of the listing. Note that the price should be quoted in its natural currency (i.e. the currency the vendor/landlord has specified), which is usually the official currency of the country that the property resides in. To be clear: this value should not be the result of a currency conversion. | 100000.00; 250 |
price_per_unit_area | Best practice (commercial) | price_per_unit_area object | The price quoted as a function of floor area. This is generally only used with commercial properties. | |
rent_frequency | Mandatory (rent) | enum | The frequency with which rent is required to be paid. | per_person_per_week,per_week,per_month,per_quarter,per_year |
price_qualifier | enum | Additional information about the price which requires emphasis, usually for legal reasons. | coming_soon,fixed_price,from,guide_price,non_quoting,offers_in_the_region_of,offers_over,sale_by_tender | |
auction | boolean | Whether the sale will be transacted by an auction. | true |
Because pricing is so important there are a number of schema-enforced dependencies for some of the pricing object's attributes. In particular:
When transaction_type = "rent", rent_frequency must be specified.
When providing a price_per_unit_area you must also provide an areas attribute with an internal area.
price_qualifier = "non_quoting" is only valid for location:country_code = "gb" and category = "commercial".
When stating price_qualifier = "non_quoting" then you must not provide pricing/price nor pricing/price_per_unit_area.
This object describes any ongoing service charges which are applicable. and charge amount must be suplied and you may optionally also supplement per_unit_area_units or frequency (or both if relevant)
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
charge | Mandatory (cannot be 0) | number | The service charge amount. | 100 |
per_unit_area_units | enum | When the charge is a function of unit area (usually for commercial properties), the units of area measurement. | sq_feet, sq_yards, sq_metres, acres, hectares | |
frequency | enum | When the charge is a fixed amount (usually for residential properties), the frequency with which the service charge is required to be paid. | per_person_per_week,per_week,per_month,per_quarter,per_year |
Use this object to indicate whether this leasehold purchase is shared ownership. If none of the sub-values are known then submit the key with an empty object, otherwise include the keys/values as appropriate.
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
percentage | number | Normally a figure from 25-75 (inclusive) but can be as low as 1 or as high as 99. Represents the proportion of ownership the purchaser will be taking on initially. | 30 | |
details | string | Any further details about shared ownership | Initial ownership % can be increased after x years |
The following fields are not mandatory, but if one is included then the other must be as well.
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
rent | Non-mandatory, but if given then rent_frequency must also be provided. | number | The amount of rent payable per rent_frequency period. | 300 |
rent_frequency | Non-mandatory, but if given then rent must also be provided. | enum | "per_day", "per_week", "per_month", "per_quarter", "per_year" |
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
type | enum | Feudal should not be used as a tenure type. Please contact customer support if requiring feudal as a listing tenure | "commonhold", "feudal", "freehold", "leasehold", "share_of_freehold", "non_traditional" |
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
details | string | Additional information specific to the commonhold arrangement (parts included in the arrangement outside of the freehold unit itself, commonhold association management structure, basic description of articles of association, etc.) |
For leasehold properties, information about the leasehold expiry and any shared ownership details should be provided if applicable.
For properties where a share of ownership is being purchased, the shared_ownership object should be provided, as below:
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
shared_ownership | shared_ownership object | Information about the share of ownership (if applicable) |
The expiry of leasehold tenure can be expressed as the actual expiry date or the number of years remaining on the lease.
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
expiry_date | Mandatory | string | The date when the lease expires. Note that this is a date-like string whose validation is not as restrictive as the datetime used for other attributes. It may be any of the following formats: YYYY-MM-DD; YYYY-MM; YYYY. | "2014-01-31"; "2014-01"; "2014" |
or
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
years_remaining | Mandatory | integer | The number of years remaining on the lease. | 99 |
For some share_of_freehold properties there may be an associated lease component. In such cases information about the lease expiry can be provided to supplement this tenure
The expiry of any lease component of a share_of_freehold tenure (if relevant) can optionally be expressed as either the actual expiry date or the number of years remaining on the lease. if provided only one of the following is permitted and not both at once
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
expiry_date | optional should not be provided if years_remaining is given | string | The date when the lease component of the share_of_freehold expires. Note that this is a date-like string whose validation is not as restrictive as the datetime used for other attributes. It may be any of the following formats: YYYY-MM-DD; YYYY-MM; YYYY. | "2014-01-31"; "2014-01"; "2014" |
or
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
years_remaining | optional but should not be provided if expiry_date is given | integer | The number of years remaining on the lease comopnent of the share_of_freehold. | 99 |
This allows you to specify the eligibility of various classifications of applicant for a tenancy. Note that you do not have to specify eligibility for all classifications.
Note: as of April 2019, the dss attribute in this object is ignored. Please see"Zoopla to end 'No DSS' wording in rental adverts" for more details.
Object attribute | Requirements | Type | Description | Example |
---|---|---|---|---|
dss | enum | The eligibility for applicants who are receiving Housing Benefit. | accepted,excluded,only | |
students | enum | The eligibility for applicants who are students. | accepted,excluded,only |
After processing your message we will send you a response that includes a standard HTTP status code and a JSON object in the content body that provides more detailed feedback.
A response with a 200 OK HTTP status code indicates a successfully processed message. For convenience the JSON response object includes the primary identifiers provided in the original message. The methods respond as follows:
{
"status": "OK",
"branch_reference": "<message's branch_reference>",
"new_branch": true
}
If this was the first time that we have received a message about branch_reference then new_branch will be true, otherwise false.
{
"status": "OK",
"listing_reference": "<message's listing_reference>",
"listing_etag": "<message's ZPG-Listing-ETag header>",
"url": "<URL for this listing>",
"new_listing": true
}
If this was the first time that we have received a message about listing_reference then new_listing will be true, otherwise false.
In both sandbox and live environments the response contains a url attribute:
in the sandbox environment, this is a link to a web page where you can preview how the listing will be displayed on our websites.
A listing/delete message will return a 200 OK if the listing_reference is no longer active on our system. If your message deleted listing_reference then you will receive:
{
"status": "OK",
"listing_reference": "<message's listing_reference>"
}
whereas if the listing_reference was already inactive, or previously unknown to us, then you will receive:
{
"status": "UNKNOWN",
"listing_reference": "<message's listing_reference>"
}
The effect is the same but you may wish to investigate these cases since this may be indicative of a synchronisation issue.
listing/list allows you to retrieve listing inventory information for a branch:
{
"status": "OK",
"branch_reference": "<message's branch_reference>",
"listings": [
{
"listing_reference": "<listing_reference 1>",
"listing_etag": "<ZPG-Listing-ETag 1>",
"url": "<URL for this listing>"
},
{
"listing_reference": "<listing_reference 2>",
"listing_etag": "<ZPG-Listing-ETag 2>",
"url": "<URL for this listing>"
}
]
}
The listing_etag attribute contains the value of the ZPG-Listing-ETag you provided with your last listing/update message relating to listing_reference. Using this value you can check the synchronicity of the listing's data between ZPG's system and yours.
The url attribute behaves in exactly the same way as that described for the listing/update response.
If branch_reference has no listings then it will not be treated as an error and an empty list will be returned:
{
"status": "OK",
"branch_reference": "<message's branch_reference>",
"listings": []
}
If there was a problem with the message then the response will include an HTTP status code in the 4xx range. The accompanying JSON response object will include more detailed information about the error to help you diagnose and fix it.
An error response will always include the following attributes:
Response attribute | Type | Description |
---|---|---|
error_name | string | A unique string identifier for the error. |
error_advice | string | A description of the error and some advice as to how to fix it. |
If there are problems parsing your message as JSON, there will also be:
Response attribute | Type | Description |
---|---|---|
request_content | string | The content body of your request (which should have been a JSON object). |
json_validation | string | The reason(s) why request_content could not be parsed as a JSON object. |
If there are problems determining which schema or method should be used, there will also be:
Response attribute | Type | Description |
---|---|---|
method | string | The method your message was sent to. |
profile | string | The JSON schema you declared your message would conform to. |
If there are problems validating the message against its associated JSON schema, there will also be:
Response attribute | Type | Description |
---|---|---|
errors | array of JSON objects | The errors that were generated when validating your message against the schema. |
schema | string | The JSON schema your message was validated against. |
status | string | This will be set to "FAILURE". (See also the status attribute returned by successful responses.) |
For example, if you were to send a correctly formatted message to the incorrect method endpoint you would receive:
{
"error_name": "schema_method_mismatch",
"error_advice": "The schema referenced in the Content-Type profile does not match the method endpoint where the message was sent. Please check that you are using the correct message schema and that the message is being sent to the correct endpoint.",
"method": "/sandbox/undefined/branch/update",
"profile": "http://realtime-listings.webservices.zpg.co.uk/docs/v2.3/schemas/listing/update.json"
}
The most common errors relate to problems with the JSON message itself (for example, invalid data or a missing mandatory attribute). The JSON validator will reference attributes of interest via a hierarchical path, with "#/" denoting the root level of the object:
#/category{
"category": "residential"
}
#/location/coordinates/latitude{
"location": {
"coordinates": {
"latitude": 120.659815,
"longitude": -7.846114
}
}
}
Note that, in JSON, array elements are referenced using a zero-based index:
#/an_array/1{
"an_array": [
"element 0 => #/an_array/0",
"element 1 => #/an_array/1",
"..."
]
}
The JSON validator's error messages should be self-explanatory when describing problems about an individual attribute and its dependencies.
The JSON validator will attempt to validate your message against the schema by interpreting the listing's data in all possible contexts. If it is unable to find a successful match then it will return all the errors it encountered. Recall that there are three principal attributes that are used to interpret the listing's data (#/location/country_code, #/category, #/pricing/transaction_type) so, naturally, there are some schema-enforced rules related to these attributes. If one of these attributes has a problem then it may trigger multiple errors (each produced by considering the message in a different context), which may make it appear as though there are more problems than there actually are, so we recommend you investigate errors for these attributes first. For example, consider the following pricing object:
{
"pricing": {
"transaction_type": "rent",
"currency_code": "GBP",
"price": 10000
}
}....
This produces two errors:
{
"error_name": "json_does_not_validate",
"error_advice": "The JSON message does not conform with the schema. Please check the 'errors' array for details.",
"errors": [
{
"message": "'rent_frequency' is a required property",
"path": "#/pricing"
},
{
"message": "'rent' is not one of ['sale']",
"path": "#/pricing/transaction_type"
}
],
"schema": "http://realtime-listings.webservices.zpg.co.uk/docs/v2.3/schemas/listing/update.json",
"status": "FAILURE"
}
The validator has attempted to interpret the message as a rent listing and discovered that the required rent_frequency attribute is missing. Having failed to validate as a rent listing, the validator then attempted to interpret the message as a sale listing instead. That failed too because the transaction_type is incorrect for a sale listing. In order to fix this error the sender would have to decide what the correct transaction_type was and then either change the transaction_type or provide the rent_frequency .
Providing a comprehensive description of the listing is very important: it is the estate agent's primary opportunity to convince the user that this property is exactly what they are looking for. Our detail page is divided into the following sections:
The description should provide an overview of the property and, if relevant, its constituent rooms. Presentation is also very important, from both structural and visual perspectives, as it allows the user to quickly find information about the property that they are specifically interested in. Unfortunately there is no standard as to how to structure descriptions, so our detailed_description attribute has been designed to be as flexible as possible, whilst providing a framework to encourage good practice.
The detailed_description is an array of description objects, each of which can have the following attributes:
These attributes populate a template with this structure:
You must provide at least one of heading or text per object, whilst dimensions is optional (but contingent on the presence of a heading). The heading will be styled appropriately. By specifying a sequence of these objects, each using various combinations of header, dimensions and text, a wide variety of complex layouts can be achieved. A number of common scenarios are discussed below.
The text can include HTML. However, we only support a limited number of HTML tags in order to prevent unforeseen and undesirable interactions with our own HTML layout and styling. We currently only support:
<br>
(line break)<p>
(paragraph)<strong>
or <b>
(highlighted)<em>
or <i>
(emphasised)<u>
(underlined)<ul>
and <li>
(unordered list)Note that any external links and contact details will be removed from the description text.
If your system only stores a single block of descriptive text then you would use one object with a single text attribute:
{
"detailed_description": [
{
"text": "This is a single block of text."
}
]
}
Because there is no information about the structure of the text when provided this way, the author may need to embed HTML tags in order to achieve the layout they desire.
If your descriptions are split into sections then you would use multiple objects, one per section, specifying a heading for each:
{
"detailed_description": [
{
"heading": "Section one",
"text": "The text for section one."
},
{
"heading": "Section two",
"text": "The text for section two."
}
]
}
Note that sections do not necessarily have to have a heading, in which case they will appear as paragraphs. A common use-case is to have an un-headed introductory paragraph, followed by headed sections:
{
"detailed_description": [
{
"text": "Introductory overview of the property."
},
{
"heading": "Section one",
"text": "The text for section one."
},
{
"heading": "Section two",
"text": "The text for section two."
}
]
}
The most common (residential) use-case is an overview paragraph followed by sections that describe individual rooms. This is exactly the same as the sectioned description discussed previously but with the addition of the dimensions attribute:
{
"detailed_description": [
{
"text": "Introductory overview of the property."
},
{
"heading": "Room one",
"dimensions": {
"length": 12.2,
"width": 10,
"units": "metres"
},
"text": "Information about room one."
},
{
"heading": "Room two",
"dimensions": "10m x 8.2m",
"text": "Information about room two."
}
]
}
If you do not have a description for a room (although that's not recommended) then you can just specify a heading in order to maintain consistency of presentation:
{
"detailed_description": [
{
"text": "Introductory overview of the property."
},
{
"heading": "Master bedroom",
"dimensions": {
"length": 20.1,
"width": 15.2,
"units": "feet"
},
"text": "A large bedroom with lots of storage space and an outlook over the valley."
},
{
"heading": "Bedroom",
"dimensions": "10' x 8'"
},
{
"heading": "Bedroom",
"dimensions": "9' x 9'"
},
{
"heading": "Kitchen",
"text": "The kitchen was recently refitted."
}
]
}
Note that in the above example the dimensions of the kitchen are missing. This is permissible but not good practice when discussing individual rooms.
A listing's content is not transferred to ZPG via the Real-time Listings Service directly. Instead the listing/update method includes a content attribute for you to specify a list of URLs from where that content can be obtained. It is likely that you already have a web server hosting this content, so this mechanism allows you to leverage your existing infrastructure to make the transfer of these assets more efficient. We support web servers using either HTTP or HTTPS.
Upon receipt of a listing/update message, we will request all the URLs specified, with appropriate HTTP headers to make the request conditional. So the first time a particular URL is mentioned we will download that content. For subsequent listing/update messages which mention that URL, we will modify our request to include the first of the following HTTP headers that we have an accompanying value for:
In this way we will only download that content again when it changes. We recommend that your system support ETags in addition to last-modified dates. Whilst the generation of the ETag is not defined by the HTTP specification, many systems use a hashing algorithm (e.g.: MD5; SHA-1) since they are only generated from the binary data itself (so file system changes do not affect it), and the likelihood of two files producing the same hash is very small. This provides a high level of confidence that when the hash changes, the content is different; and vice versa.
Your web server probably behaves correctly when sent these headers already, particularly if you are using a commercial content delivery network. However, we nevertheless recommend you check its behaviour to be sure - especially since web browsers use the same mechanism to maintain their local data cache, so a misconfiguration could be enhancing your network traffic significantly.
Our download process will identify itself as:
User-Agent: Zoopla Property Group automated download
If your content will be hosted on a private web server and therefore wish to use firewall rules to restrict access, please whitelist the following IPs:
We only support web-safe formats for content. Acceptable MIME types are:
Images can strongly influence a user's impression of a listing so it is important to provide good quality images which are representative of the property.
Mobile device | Screen resolution |
---|---|
iPhone 3 (and previous generations) | 480 x 320 |
iPhone 4 | 960 x 640 |
iPhone 5 (all variants) | 1136 x 640 |
iPhone 6 | 1334 x 750 |
iPhone 6 Plus | 1920 x 1080 |
Google Nexus 5 | 1920 x 1080 |
HTC One | 1920 x 1080 |
Samsung Galaxy 5 | 1920 x 1080 |
iPad Mini | 1024 x 768 |
iPad Retina display | 2048 x 1536 |
iPad Air | 2048 x 1536 |
Floor plans are also of great interest to our users when attempting to visualise the property. It is important to provide high resolution images for floor plans because otherwise text can become illegible.
This section describes the workflow for how the ZPG Real-time Listings Service should be used and how to ensure that the data ZPG has is synchronised with your own.
For each branch that the estate agent owns, you send a branch/update.
For each added branch, find the set of listings that they are responsible for. For each listing, send a listing/update message.
Recall that listing/update requires that it be accompanied by a ZPG-Listing-ETag HTTP header. The value of ZPG-Listing-ETag should be an identifier on your system which allows you to accurately determine that when two such values are different, the overall state of the listing is also different. Depending on how you track changes to your data (and how it is represented in a listing/update message) an auto-incrementing revision counter, or possibly a last-modified date may be suitable. However, we would recommend using a checksum based on the listing/update message itself:
Send a listing/update message which details the complete state of the updated listing.
Send a listing/delete message to delete it from our system.
Because of the incremental nature of the updating process, should a message be lost (e.g. due to a networking problem), then the data that ZPG has will be different to yours and will need correcting. We therefore recommend that you periodically, once a week say, check the synchronisation of data:
For each branch you maintain, send a listing/list request. In the response, for each of the branch's listings, we will provide you with your listing_reference and the ZPG-Listing-ETag that we last received for that listing.
If listing/list is missing a particular listing, use listing/update to create it.
If listing/list includes a listing that is no longer valid, use listing/delete to remove it.
For each listing that is common to both systems, compare the value of the ZPG-Listing-ETag with that of the relevant field in your system:
If the values are identical then the data is the same on both systems and you do not need to do anything. This should be the normal case.
If the values are different then ZPG's data is stale and you should use listing/update to refresh it.
If you currently send ZPG a bulk data feed then it may be useful to understand how the transition between that feed and the ZPG Real-time Listings Service will be handled before reading about how to build your implementation.
Data feeds received by ZPG are kept separate from each other: your data never interacts with anyone else's (nor theirs with yours) and should you send us multiple feeds they will not interact with each other either. We then choose which subsets of these data feeds will be shown on our websites (on a per-branch basis).
You should therefore design your system so that you can update ZPG via your bulk data feed and the Real-time Listings Service concurrently, thus maintaining two equivalent data sets simultaneously:
Once your Real-time Listings Service integration is complete and running smoothly, ZPG can then simply switch its websites over from using one data set to the other. This mechanism preserves your data's integrity; simplifies testing; makes it easier to QA attribute coverage and equivalence between both systems; and allows for a quick transition to having real-time behaviour for all branches simultaneously - if desired. (It also provides the security of a viable rollback option in the unlikely event that a major problem occurs during the migration.)
This is an exact copy of the live environment but is isolated from our public websites. Any test messages you send here will only affect the data you previously sent to the sandbox environment; you cannot "break" anything. There are no restrictions on the number of messages you can send or listings you can store. Indeed, as part of your final testing you should maintain a copy of all your listing data in the sandbox environment (just as you would do in the live environment) in order to demonstrate that the system is mature and suitable for sending data to our public websites in real-time.
You can more easily visualise a particular listing's data via our listing preview page. Please note that whilst the preview is styled in a similar fashion to our websites it is only intended for illustrative purposes. The URL for a particular listing's preview page can be found in the responses from listing/update and listing/list.
The preview page will indicate whether we will be able to download the associated image and other content URLs, and for any images we could not access an "awaiting photos" placeholder will be shown. Please see 9. Retrieval of media content for more information about how we will retrieve your content and the set of IPs our download requests will originate from.
Whilst you do not have to follow this exactly, we suggest:
Once you have a working system, it is important to thoroughly test it:
It is expected that your system will communicate with the sandbox environment using actual data on a continual basis for at least a week, in order to prove that the combined system is stable, produces no unexpected errors and has no synchronisation issues. When you are happy that this is the case and it is therefore suitable to become the sole means of sending us listing data, please let us know so that you can be granted access to the live environment. The migration procedure is very similar to that used when testing in the sandbox environment:
Provide us with the details of all your branches. Please contact us if you do not wish to supply them via the branch/update method.
Send listing/update messages for all listings on your system to the live environment. (This is most easily achieved by running your synchronisation process. Please let us know when this initial upload has been completed.)
Send listing/update and listing/delete messages in real-time as agents edit their data.
Periodically check the synchronisation of data between your system and ours via listing/list.
Because the updating process will already have been shown to work correctly over an extended period in the sandbox environment, there should be no difficulties when using the live environment.
If you currently send ZPG a bulk data feed, please continue sending this to us - even after you start sending real-time updates to the live environment. Once your initial upload of data to the live environment has completed, please let us know. We will then change our branch configuration so that we stop using the listing data in your old bulk data feed and start using the data sent via the ZPG Real-time Listings Service instead. When we complete this branch migration process, we will inform you so that you can then terminate your old bulk data feed.
We hope that having read this documentation you have decided to integrate the ZPG Real-time Listings Service with your system.
If you have any questions about this documentation, schemas or the service in general, please contact our Support Team.
Thank you for your commitment to improving the quality of service that our mutual clients and users will receive by integrating your system with the ZPG Real-time Listings Service.
The majority of our boolean attributes are optional. You should only include a boolean attribute where you are confident that the value is correct; do not set it to a default value. The reason for this is that you may convey a meaning that you did not intend. For example if you were to default pets_allowed to:
Omitting boolean attributes where you do not know the correct value also has the benefit of reducing message sizes and making them easier to read when debugging.
Dates should be expressed using standard ISO format: YYYY-MM-DD. Where appropriate, a time component may be included by appending the date with a literal T character separator, followed by the time as hh:mm:ss. Note that the time component should use the local time zone of the property. For example:
The quality of text supplied in free-text string attributes can vary considerably. In order to improve the user experience on our websites we may modify the display of these strings in order to present a consistent style and aid comprehension (e.g.: capitalisation; removal of HTML tags). If the quality of the text is particularly poor then, in some circumstances, we may choose not to display it at all (e.g. invalid data for the attribute). Care should therefore be taken at the initial data-entry stage to ensure that the correct attribute is being populated and that free-text intended to be read by the public is maintained appropriately (e.g.: spelling; grammar).
Our schemas use a regular expression to ensure that free-text attributes:
Note that carriage returns (\r
) and newlines (\n
) are considered whitespace.
These rules are enforced by the schema via a regular expression, which will be included in any validation errors:
does not match '^\\S(|(.|\\n)*\\S)\\Z'
If you encounter this error you may find it easier to re-read the validation rules above in order to correct the text.
Please refer to 7.2 Errors for more information on error responses.
All costs/prices should be quoted in the currency specified by pricing:currency_code.
display_address is an optional attribute since it can be constructed from the dedicated address attributes: "street_name, locality, town_or_city". We recommend software providers provide a dedicated field for property_number_or_name, so that unique property address information will not be included in a constructed address. Software providers should encourage their clients to populate address attributes correctly, and to only use the display_address field when address information is conflicting and shows incorrectly on our site.
The layout of floors within a multi-storey building is defined as follows:
There are a lot of terms for describing house types. The distinctions between some of these types are sometimes unnecessary (for example: apartment vs flat) and broader groupings that just convey the core aspects of the architecture are preferred. Consequently we only support a relatively limited number of property types. When deciding which property type to use, you should choose the most applicable property type that we support. If you believe that there is a significant difference between your property type and those that we support, then send your property type as a readable string. In such cases we will display property type as "Property", but the string you supplied will be considered during our periodic review of property types to ensure that we are supporting the needs of our users adequately. (Please note that our supported property_type enums use all-lowercase characters; alternative case-variants will be displayed as "Property".)
Some property_types in your system may be conveyed by the appropriate use of other attributes. For example:
When category = "residential", our schema will reject property_type = "studio" if total_bedrooms is also present and has a value greater than 1, as we cannot determine which value is inaccurate; see 7.2.2 JSON schema validation for more information about how we reject ambiguous messages.
Note that the display of the property_type is also dependent on the associated country_code and category of the listing. The schema does not enforce these rules. If an inappropriate property_type is specified for a particular country_code-category combination then it will be displayed as "Property" (residential) or "Commercial Property" (commercial). The list of supported property_types and their validity is as follows:
property_type | Display string | UK residential | Overseas residential | UK commercial | Overseas commercial |
---|---|---|---|---|---|
barn_conversion | Barn conversion | ✓ | ✓ | ||
block_of_flats | Block of flats | ✓ | ✓ | ✓ | ✓ |
bungalow | Bungalow | ✓ | ✓ | ||
business_park | Business park | ✓ | ✓ | ||
chalet | chalet | ✓ | |||
chateau | Château | ✓ | |||
cottage | Cottage | ✓ | ✓ | ||
country_house | Country house | ✓ | ✓ | ||
detached | Detached house | ✓ | ✓ | ||
detached_bungalow | Detached bungalow | ✓ | ✓ | ||
end_terrace | End terrace house | ✓ | ✓ | ||
equestrian | Equestrian property | ✓ | ✓ | ||
farm | Farm | ✓ | ✓ | ✓ | ✓ |
farmhouse | Farmhouse | ✓ | ✓ | ||
finca | Finca | ✓ | |||
flat | Flat | ✓ | ✓ | ||
hotel | Hotel/guest house | ✓ | ✓ | ||
houseboat | Houseboat | ✓ | ✓ | ||
industrial | Industrial | ✓ | ✓ | ||
land | Land | ✓ | ✓ | ✓ | ✓ |
leisure | Leisure/hospitality | ✓ | ✓ | ||
light_industrial | Light industrial | ✓ | ✓ | ||
link_detached | Link-detached house | ✓ | ✓ | ||
lodge | Lodge | ✓ | ✓ | ||
longere | Longère | ✓ | |||
maisonette | Maisonette | ✓ | ✓ | ||
mews | Mews house | ✓ | ✓ | ||
office | Office | ✓ | ✓ | ||
park_home | Mobile/park home | ✓ | ✓ | ||
parking | Parking/garage | ✓ | ✓ | ✓ | ✓ |
pub_bar | Pub/bar | ✓ | ✓ | ||
restaurant | Restaurant/cafe | ✓ | ✓ | ||
retail | Retail premises | ✓ | ✓ | ||
riad | Riad | ✓ | |||
semi_detached | Semi-detached house | ✓ | ✓ | ||
semi_detached_bungalow | Semi-detached bungalow | ✓ | ✓ | ||
studio | Studio | ✓ | ✓ | ||
terraced | Terraced house | ✓ | ✓ | ||
terraced_bungalow | Terraced bungalow | ✓ | ✓ | ||
town_house | Town house | ✓ | ✓ | ||
villa | Villa | ✓ | |||
warehouse | Warehouse | ✓ | ✓ |
Date | Version | Schema(s) changed | Change description |
---|---|---|---|
2025-01-31 | v2.3 | listing/update | updatebuyer_incentives with additional terms "own_new_rate_reducer", "deposit_unlock" "part_exchange", as valid buyer_incentives |
2024-03-19 | v2.3 | listing/update | "construction_materials" added - optional attribute listing of strings declaring notable materials in a buildings construction "water_supply" added - optional attribute listing of fixed values indicating one or more sources of water to the property "heating_source" added - optional attribute listing of fixed values indicating one or more supplies of heating to the property "sewerage_supply" added - optional attribute listing of fixed values which best describe sewage managment for the property "broadband_supply" added - optional attribute listing of fixed values accurately describing the nature of the supply (or supplies) of broadband to the property "electricity_supply" added - optional attribute listing of fixed values which describe how electrical power is supplied to the property "parking" extended with new fixed values which describe the parking options at the property "building_safety_issues" added - optional attribute listing of strings declaring notable building safety concerns at this address "risks" added - optional object containing relevant environmental property risks. includes "flooding_risks", "coastal_erosion_risk" and "mining_risks" as different risk categories "known_planning_considerations" added - optional attribute free-text field declaring any known or notable property planning concerns/permissions at this address or nearby "restrictions" and "rights_and_easements" added - optional attributes listing of fixed values which best describe any known or notable property restrictions and easements expanded "accessibility" options. now prevents duplicate values and empty list. description edited to clarify added "uprn" optional attribute. is a string of 1-12 characters max |
2024-03-04 | v2.2 | listing/update | Tenure added - "non_traditional" is now an possible "tenure" Extended "tenure:share_of_freehold" with optional "years_remaining" or "expiry_date" for any lease component (if relevant). Deprecated and removed "review_period" from service_charge object. In the ground_rent object, deprecated "percentage_increase", added "date_of_next_review". |
2023-08-01 | v2.1 | listing/update | Firstly, the accessibility feature has shifted from a boolean value to an enum list, now encompassing "lateral_living", "step_free_access", "wheelchair_accessible", and "wet_room". Secondly, the "shared_ownership" object has been expanded to include a new field called "details." Added a new field to shared_ownership object |
2022-06-22 | v2.0 | listing/update | Addition of NTS fields and adjustments to existing structures to support these. Added a domestic_rates object to cover the to expand the newly added Northern Ireland domestic_rates. This greatly restructures this attirbute to provide detail as to why the band would be unknown (new developments), and where a property is excluded from domestic rates. strictly speaking this should only apply to Northen Island properties though this is not enforced here. |
2022-06-22 | v2.0 | listing/update | Addition of NTS fields and adjustments to existing structures to support these. Converted "tenure" from a simple string to the tenure object, supporting sub-items specific to that tenure type. Removed "shared_ownership" from buyer_incentives into the tenure[type=leasehold]:shared_ownership -specific entry. Added a local_authority object to cover the moved council_tax_band and the newly added Northern Ireland domestic_rates. council_tax_band has also been restructured to provide detail as to why the band would be unknown (new developments), and where a property is exempt from council-tax. Converted ground_rent from a single number to the ground_rent object to permit the addition of review_period and percentage_increase values. The original numeric value of ground_rent can now be submitted under the amount element of said object. Added "coming_soon" as a pricing:price_qualifier and removed "price_on_application". Added review_period to service_charge object Moved lease_expiry values (expiry_date and years_remaining) under tenure[type=leasehold] Added the letting_arrangements field to allow for descriptions of non-standard letting arrangements. |
2017-06-14 | v1.2 |
| Ensured the constraints within the location object in the branch/update schema matched those in the listing/update schema. Added support for equity_loan to buyer_incentives. Removed constraint on the maximum value of all epc_ratings object attributes, and sap_rating. Updated the JSON schema draft v4 link on the schemas page. |
2015-08-10 | v1.1 | listing/update | Added support for per_person_per_week frequency to service_charge:frequency and pricing:rent_frequency. Implemented constraints for pricing:price_qualifier = "non_quoting" when location:country_code = "gb" and category = "commercial". |
2015-05-13 | v1.0 |
| Promoted version 0.1 to 1.0. |
2015-05-08 | v0.1 | listing/update | Changed the constraints concerning location:property_number_or_name and location:street_name so that at least one must be provided. |
2015-03-19 | v0.1 | listing/update | Changed the constraints surrounding shared_accommodation and available_bedrooms. |
2015-03-19 | v0.1 | listing/update | Corrected the spelling of shared_accommodation. |
2015-03-13 | v0.1 | listing/update | Fixed a bug with how total_bedrooms and property_type = "studio" interact. |
2015-01-07 | v0.1 | = listing/update = | Added sap_rating attribute. |
2014-12-11 | v0.1 | listing/update | Fixed constraints for residential listings so that total_bedrooms and bathrooms are not mandatory, as per the documentation. |
2014-12-10 | v0.1 |
| Updated regular expression validation for free-text attributes. |
2014-11-21 | v0.1 | branch/update | Updated regular expression validation for attributes containing URL data so they are consistent: no whitespace is allowed. Where necessary, whitespace and other meta characters should be URI-encoded. |
2014-11-14 | v0.1 | listing/update | Updated the list of supported property_types so they are consistent with the documentation. |
2014-11-10 | v0.1 | listing/update | Fixed typo in attribute name administration_fees Added document to the list of valid type values for a content object. |
2014-09-12 | v0.1 |
| Initial draft. |