BROKER API

Broker API

A read contract for a White Label or Managed book. Pull derived figures into your own CRM, keyed by your own client reference.

These paths are the contract. This site does not serve them, so a call does not return data.

A key is for a principal of a White Label or Managed organisation. The secret is shown once, with a visible prefix. Creating a key is not on this site.

Send the key as a bearer token: Authorization: Bearer YOUR_API_KEY.

Scopes are read:clients, read:properties and read:signals.

60 requests a minute per key. Above that, the contract is HTTP 429 with a Retry-After header.

A response does not include an email address or a phone number.

Every response body carries an attribution field with this text: Source: Dubai Land Department open data via Data.Dubai, analysed by Freehold Index.

How a figure is produced is described here: How these figures are produced

Read endpoints
MethodPathReturns
GET/api/v1/clientsLook up by reference or by an email address you already hold. Returns the client id, name, reference, assigned agent and apartment count.
GET/api/v1/clients/{id}/propertiesEach apartment: building, unit, bedrooms, estimate and range, monthly change, rent, gross and net yield, rating, data level and period.
GET/api/v1/clients/{id}/summaryTotal estimated value, weighted yield, open signals by type, and when the last estimate summary was sent and opened.
GET/api/v1/signals?since={iso date}Unacknowledged signals for the organisation since the given time.

HubSpot custom code

A HubSpot custom-code action can call the summary path. Replace YOUR_API_KEY with a key held in the HubSpot secret store. Do not paste a key into this page.

exports.main = async (event, callback) => {
  const clientId = event.inputFields.client_id;
  const url = "https://freeholdindex.com/api/v1/clients/" + encodeURIComponent(clientId) + "/summary";
  const token = "YOUR_API_KEY";
  const response = await fetch(url, {
    headers: { Authorization: "Bearer " + token },
  });
  const body = await response.json();
  callback({
    outputFields: {
      http_status: String(response.status),
      attribution: body && typeof body.attribution === "string" ? body.attribution : "",
    },
  });
};