Field Reference
Every field of the property, agency and agent objects. Names, types and requiredness are identical for JSON and XML — only the serialization differs.
All field names are camelCase and match the downstream HAVHO Property Feed contract exactly. Send numbers as numbers, dates as ISO-8601, and omit optional fields you have no value for rather than sending null or "".
providerId must be a stable, agreed identityNever send providerId on a property, agent, agency or deletion — it is set on our side, once, for the feed as a whole, and returned on every one of those records. It must be agreed with the consumer up front and must not change once that agreement is made (a staging value and a production value are normally different, deliberately chosen strings, e.g. havho-sandbox). It is not derived from anything that can shift on its own — not a database row id, not an internal feed number.
The normal way to set it is explicitly, on the feed's own configuration. If you would rather agree it up front and have us capture it automatically, your feed document (not any property/agent/agency inside it) may declare a top-level providerId — see JSON / XML Format. That value is read only the first time this feed imports, when nothing has been agreed yet, and is immediately locked in on our side; a later pull sending a different value is logged and ignored rather than applied, so the identity stays stable even if your own value ever drifts.
Agency
The organisation a listing belongs to. Sent as the agency object inside each property and stored with it (agency_id, agency_name). Keyed by id.
| Field | Type | Required | Notes |
|---|---|---|---|
id | string | Required | Permanent, unique id for the organisation. Must not change if the agency renames, moves or is restructured. Max 255 chars. |
name | string | Required | Agency / organisation name. |
providerId | string | Optional | Set automatically from the feed; do not send it. |
sourceUpdatedAt | string (ISO-8601) | Optional | Set automatically when the record is stored or its values change. Only send it if your source has a reliable timestamp. |
Agent
The person responsible for a listing. Sent as the agent object inside each property, linked to that property's agency and stored with the property (agent_* columns). Keyed by id.
| Field | Type | Required | Notes |
|---|---|---|---|
id | string | Required | Permanent, unique id. Must stay the same if the agent changes name, email, phone, office, agency, or location. Max 255 chars. |
providerId | string | Optional | Set automatically from the feed and always the same as the agency's; do not send it. The REST API returns it. |
fullName | string | Required | Agent's full name. |
email | string | Required | Agent's email address. |
phone | string | Required | Agent's contact number, including country code where possible. |
sourceUpdatedAt | string (ISO-8601) | Optional | Set automatically when the record is stored or its values change. Only send it if your source has a reliable timestamp. |
location | string | Optional | Free-text location / area the agent works. |
photoUrl | string (HTTPS URL) | Optional | Agent profile image, absolute HTTPS URL pointing at the file. |
ffcNumber | string | Optional | Fidelity Fund Certificate number. |
Property listing
An active listing with its agency and agent nested inside it. Keyed by id. A feed is just an array of these.
Identity & relationships
| Field | Type | Required | Notes |
|---|---|---|---|
id | string | Required | Permanent, unique id of the listing. Sole key for create / update / removal matching. Max 255 chars. |
agent | object | Required | The responsible Agent, nested inside the property. |
agency | object | Required | The owning Agency, nested inside the property. |
providerId | string | Optional | Set automatically from the feed; do not send it. |
sourceUpdatedAt | string (ISO-8601) | Optional | Set automatically when the record is stored or its values change. Only send it if your source has a reliable timestamp. The REST API returns it on every record. |
Classification
| Field | Type | Required | Allowed values / format |
|---|---|---|---|
type | string | Required | sale | rent |
status | string | Optional | Leave it out: everything in properties is an active listing. If you send it, it must be active. |
propertyType | string | Required | house | apartment | townhouse | vacant land | farm/ smallholding | commercial property | industrial property | development |
title | string | Required | Listing headline. |
description | string | Required | Plain text or simple HTML. HTML entities are decoded on import. |
Pricing
| Field | Type | Required | Notes |
|---|---|---|---|
price | number | Required | Numeric ZAR, no symbols or thousands separators (4250000, not R 4,250,000). Up to 2 decimals. For type: "rent" this is the monthly amount. |
Location
| Field | Type | Required | Notes |
|---|---|---|---|
address | string | Required | Full property address, single line. Max 500 chars. |
suburb | string | Recommended | Suburb. |
city | string | Recommended | City / town. |
province | string | Recommended | Province. |
Size & structure
| Field | Type | Required | Notes |
|---|---|---|---|
beds | integer | Optional | Bedrooms, whole number ≥ 0. |
baths | integer | Optional | Bathrooms, whole number ≥ 0. |
garage | integer | Optional | Garages, whole number ≥ 0. |
parking | integer | Optional | Open parking spaces, whole number ≥ 0. |
erfSize | number | Optional | Erf / land size, in m². |
unitSize | number | Optional | Unit / building size, in m². |
Media
| Field | Type | Required | Notes |
|---|---|---|---|
photoUrls | array<string> | Required | 1 to 21 unique absolute HTTPS URLs, in display order. The first is the primary / thumbnail image. URLs must point directly at the file and stay reachable while the listing is active. |
Features & availability
| Field | Type | Required | Notes |
|---|---|---|---|
features | array<string> | Optional | Free-text labels, up to 100 per listing and 100 characters each (e.g. Borehole, Solar Inverter, Sea Views). Labels are trimmed, de-duplicated case-insensitively and kept as sent. These five known labels also drive the site's filters and are normalised to this exact spelling: Pet friendly, Garden, Flatlet, Pool, Security Estate. Commas inside a label are replaced by a space. |
availableNow | boolean | Rentals | Required when type: "rent". Whether the unit is available immediately. |
availableFrom | string (date) | Rentals | Required when type: "rent". YYYY-MM-DD. |
Removed listing
Optional. You do not need to send removals: a listing that is no longer in properties is deleted from our database automatically on the next sync (only after a complete, readable snapshot). If you do send a top-level deletions array it is honoured and recorded with your reason.
Identity. A distinct deletion event is the combination of providerId, listingId and deletedAt. The same event is never returned twice by the REST API /property-deletions endpoint, which also adds a stable deletionId (derived from those three values) so consumers can de-duplicate. If a listing is removed, re-listed and removed again, each removal is a separate event with its own deletedAt. Feeds may repeat a deletion on every pull; the importer collapses identical events.
| Field | Type | Required | Notes |
|---|---|---|---|
providerId | string | Required | Upstream source system id. |
listingId | string | Required | The id of the listing that was removed. |
deletedAt | string (ISO-8601) | Required | When the listing was removed. |
reason | string | Required | sold | rented | withdrawn | expired | deleted | source_removed |
How the records link
Property id: "CPT-S-1842"
↳ agency id: "AGY-77"
↳ agent id: "AGT-1049"
These ids stay stable when ordinary listing, agent, or agency information changes.
Namespaces. The listing, agent and agency ids are unique within a provider, not across providers. The provider is the feed itself, identified by its providerId (set on the feed's configuration, or captured once from the feed document's own top-level providerId — see the callout near the top of this page — never sent per-record). An agent has no namespace of its own: it always shares its agency's, and the REST API returns that providerId on every agent record. The same agent / agency repeats on each of its properties and is de-duplicated by id.
This page describes what you send us. For what a consuming application reads back — different field names, pagination, incremental sync — see the REST API Reference.