Every API here is available over the APIs.io API and to AI agents over MCP.
{
"openapi": "3.1.0",
"info": {
"title": "Dubai Wealth Index HTTP API",
"version": "1.1.0",
"summary": "Independent property intelligence: registered Dubai prices, rents and returns: apartments by building and by area, villas and townhouses by community.",
"description": "Registered Dubai prices, rents, gross yields and short-term rates, apartments by building and area, villas by community, published as data. Medians of Dubai Land Department sale transactions and Ejari rental contracts, prices actually paid. Current data edition: 2026-11-04.\n\nFree, with no API key and no quota. The JSON records need no account; the CSV downloads need a free account (401 signed out), and the city-wide CSV is a Pro export. Long record lists in the page renditions carry their latest 10 rows; the full lists need a free account, through the MCP server.\n\nAgents should prefer the MCP server at https://dubaiwealthindex.com/api/mcp, which exposes the same data as typed tools with the caveats attached to every figure. Its manifest is at https://dubaiwealthindex.com/.well-known/mcp.json. Every MCP request is authenticated, initialize included: a client registers itself through dynamic client registration and a person approves one consent screen, so no one has to issue you a key.\n\nQUOTING: yields are gross. Rents are registered contracts. Short-term occupancy is a stated assumption, never a measurement. A null is a suppressed figure, not a zero. Every record carries a prebuilt citation: use it.",
"contact": {
"name": "Dubai Wealth Index",
"email": "hello@dubaiwealthindex.com",
"url": "https://dubaiwealthindex.com/contact"
},
"license": {
"name": "Source data: Dubai Land Department open data",
"url": "https://dubailand.gov.ae/en/open-data/"
},
"termsOfService": "https://dubaiwealthindex.com/terms"
},
"servers": [
{
"url": "https://dubaiwealthindex.com",
"description": "Production"
}
],
"externalDocs": {
"description": "The same surfaces, in prose",
"url": "https://dubaiwealthindex.com/docs/api"
},
"x-mcp": {
"description": "The Model Context Protocol server over the same data. 26 tools (all read-only except request_info, which sends a user-confirmed enquiry to the partner brokerage), 5 resources, 5 prompts. Streamable HTTP. Every request is authenticated, initialize included: a request without a token answers 401 with a WWW-Authenticate challenge naming the metadata document, so a client authorizes once at connect and every tool works from the first call.",
"endpoint": "https://dubaiwealthindex.com/api/mcp",
"manifest": "https://dubaiwealthindex.com/.well-known/mcp.json",
"documentation": "https://dubaiwealthindex.com/docs/mcp"
},
"x-onboarding": {
"freeTier": true,
"apiKeyRequired": false,
"accountRequired": false,
"selfServe": true,
"rateLimited": false,
"notes": "These HTTP endpoints need no credential of any kind. The MCP server needs an OAuth token, obtainable end-to-end by a machine: dynamic client registration is open, so a client registers itself and a human only approves the consent screen."
},
"paths": {
"/{path}": {
"get": {
"operationId": "getPageAsMarkdown",
"summary": "Any page as markdown, at its canonical URL",
"description": "Returns any page on this site as markdown instead of HTML, at the same canonical URL. Reach for this when you want a whole page, its tables, its caveats, its links, without parsing HTML. Every rendition carries the canonical link, the data date, the sources, and the citation format. A client that accepts neither markdown nor HTML gets 406.",
"parameters": [
{
"name": "path",
"in": "path",
"required": true,
"description": "Any canonical path on the site, without the leading slash. Enumerate them from /sitemap.xml.",
"schema": {
"type": "string"
}
},
{
"name": "Accept",
"in": "header",
"required": true,
"description": "Send `text/markdown` to get the markdown rendition. q-values are honoured per RFC 9110, and an equal-weight tie resolves to HTML so browsers are unaffected.",
"schema": {
"type": "string",
"const": "text/markdown"
}
}
],
"responses": {
"200": {
"description": "Any page as markdown, at its canonical URL",
"content": {
"text/markdown": {
"schema": {
"type": "string"
}
}
}
},
"404": {
"description": "No such page or record.",
"content": {
"application/problem+json": {
"schema": {
"type": "object",
"title": "Problem",
"description": "RFC 9457 problem details. Every JSON surface here fails in this shape; branch on `code`, and `hint` says what to do next.",
"properties": {
"type": {
"type": "string",
"format": "uri",
"const": "https://dubaiwealthindex.com/docs/api#errors"
},
"title": {
"type": "string"
},
"status": {
"type": "integer"
},
"detail": {
"type": "string",
"description": "What went wrong with this request."
},
"code": {
"type": "string",
"enum": [
"not_found",
"bad_request",
"unauthorized",
"rate_limited",
"not_acceptable",
"server_error"
],
"description": "The stable machine token. Closed set: branch on this."
},
"hint": {
"type": "string",
"description": "What the caller should do next."
}
},
"required": [
"type",
"title",
"status",
"detail",
"code",
"hint"
]
}
}
}
},
"406": {
"description": "Nothing this endpoint can produce is acceptable.",
"content": {
"application/problem+json": {
"schema": {
"type": "object",
"title": "Problem",
"description": "RFC 9457 problem details. Every JSON surface here fails in this shape; branch on `code`, and `hint` says what to do next.",
"properties": {
"type": {
"type": "string",
"format": "uri",
"const": "https://dubaiwealthindex.com/docs/api#errors"
},
"title": {
"type": "string"
},
"status": {
"type": "integer"
},
"detail": {
"type": "string",
"description": "What went wrong with this request."
},
"code": {
"type": "string",
"enum": [
"not_found",
"bad_request",
"unauthorized",
"rate_limited",
"not_acceptable",
"server_error"
],
"description": "The stable machine token. Closed set: branch on this."
},
"hint": {
"type": "string",
"description": "What the caller should do next."
}
},
"required": [
"type",
"title",
"status",
"detail",
"code",
"hint"
]
}
}
}
}
}
}
},
"/md/{path}": {
"get": {
"operationId": "getMarkdownRendition",
"summary": "The same markdown at its own URL",
"description": "The markdown rendition at a URL of its own, for when the format has to be part of the cache key rather than negotiated. Prefer content negotiation on the canonical URL; use this when you cannot control request headers. Marked noindex, and it redirects to the canonical form where one exists.",
"parameters": [
{
"name": "path",
"in": "path",
"required": true,
"description": "The canonical path, without the leading slash.",
"schema": {
"type": "string"
}
}
],
"responses": {
"200": {
"description": "The same markdown at its own URL",
"content": {
"text/markdown": {
"schema": {
"type": "string"
}
}
}
},
"404": {
"description": "No such page or record.",
"content": {
"application/problem+json": {
"schema": {
"type": "object",
"title": "Problem",
"description": "RFC 9457 problem details. Every JSON surface here fails in this shape; branch on `code`, and `hint` says what to do next.",
"properties": {
"type": {
"type": "string",
"format": "uri",
"const": "https://dubaiwealthindex.com/docs/api#errors"
},
"title": {
"type": "string"
},
"status": {
"type": "integer"
},
"detail": {
"type": "string",
"description": "What went wrong with this request."
},
"code": {
"type": "string",
"enum": [
"not_found",
"bad_request",
"unauthorized",
"rate_limited",
"not_acceptable",
"server_error"
],
"description": "The stable machine token. Closed set: branch on this."
},
"hint": {
"type": "string",
"description": "What the caller should do next."
}
},
"required": [
"type",
"title",
"status",
"detail",
"code",
"hint"
]
}
}
}
}
}
}
},
"/data/buildings/{area}/{building}.json": {
"get": {
"operationId": "getBuildingRecord",
"summary": "One building's numbers as data",
"description": "The versioned JSON record for one published apartment building: median registered sale prices and rents, gross yield and its basis, growth, turnover upside, off-plan uplift and the forward short-term curve, all by bedroom type. Reach for this rather than the markdown page when you want figures rather than a document. Figures are medians of registered Dubai Land Department sales and Ejari contracts. The record carries its own citation and canonical URL, so a figure taken from it keeps the link back.",
"parameters": [
{
"name": "area",
"in": "path",
"required": true,
"description": "Area slug from a canonical URL, e.g. \"business-bay\".",
"schema": {
"type": "string",
"pattern": "^[a-z0-9][a-z0-9-]{0,79}$"
}
},
{
"name": "building",
"in": "path",
"required": true,
"description": "Building slug, e.g. \"vera-tower\".",
"schema": {
"type": "string",
"pattern": "^[a-z0-9][a-z0-9-]{0,79}$"
}
}
],
"responses": {
"200": {
"description": "One building's numbers as data",
"content": {
"application/json": {
"schema": {
"type": "object",
"title": "BuildingRecord",
"description": "The versioned record for one published apartment building. Identical to what the MCP `get_building` tool returns, so a citation from either resolves the same way.",
"properties": {
"schemaVersion": {
"type": "string",
"description": "Version of this record shape. Additive changes bump the minor; a breaking one would bump the major and be announced on /docs."
},
"type": {
"type": "string",
"const": "DubaiWealthIndexBuildingRecord"
},
"id": {
"type": "string",
"format": "uri",
"description": "Stable absolute identifier for the record, of the form <canonicalUrl>#record. It does not change across data refreshes. Grain: one building record. When null: Never null."
},
"canonicalUrl": {
"type": "string",
"format": "uri",
"description": "The human-readable page this record mirrors. Cite this, not the JSON URL. Grain: one building record. When null: Never null."
},
"name": {
"type": "string",
"description": "The building's name as published."
},
"area": {
"type": "object",
"description": "The Dubai area this building sits in.",
"properties": {
"name": {
"type": "string"
},
"slug": {
"type": "string"
},
"locality": {
"type": "string"
},
"country": {
"type": "string"
}
}
},
"purpose": {
"type": "string",
"enum": [
"all",
"sale",
"rent"
],
"description": "Which market's rows this record carries."
},
"dataAsOf": {
"type": "string",
"format": "date",
"description": "The edition of the registered data every figure in the record was computed from. Quote it with any figure taken from here. Unit: ISO date. Grain: the whole record. When null: Never null on a published record."
},
"sources": {
"type": "array",
"items": {
"type": "string"
},
"description": "The registries the figures came from. Airbnb appears only where short-term metrics are present. Grain: the whole record. When null: Never null."
},
"methodologyUrl": {
"type": "string",
"format": "uri"
},
"attribution": {
"type": "object",
"title": "Attribution",
"description": "A prebuilt citation for this record in three formats. Copy the one matching your output format rather than composing your own; a figure quoted without its link back is the failure this block exists to prevent.",
"properties": {
"plain": {
"type": "string"
},
"markdown": {
"type": "string"
},
"html": {
"type": "string"
}
}
},
"metrics": {
"type": "array",
"items": {
"type": "object",
"title": "MetricRow",
"description": "One building × bedroom × purpose. A null is a suppressed figure, never a zero. Rows carry some fields that are not yet in the published field reference at /docs/data-dictionary; only the documented ones below are stable, and an undocumented field may change or disappear without notice.",
"properties": {
"bedroom": {
"type": "string",
"enum": [
"all",
"studio",
"1br",
"2br",
"3br",
"4br_plus"
],
"description": "One of all, studio, 1br, 2br, 3br, 4br_plus. \"all\" is the building-wide median across every unit size, not a sum or an average of the rows below it. Grain: one metric row. When null: Never null."
},
"purpose": {
"type": "string",
"enum": [
"sale",
"rent"
],
"description": "Which market the row measures: sale, rent, offplan or short_let. A building has a row per bedroom type per purpose. Grain: one metric row. When null: Never null."
},
"medianPrice": {
"type": [
"number",
"null"
],
"description": "Median registered sale price: the middle of what units actually sold for. Unit: AED. Grain: building × bedroom, trailing 12 months. When null: Too few registered sales in the window to publish a median that would hold. It does not mean nothing sold."
},
"medianPriceSqft": {
"type": [
"number",
"null"
],
"description": "Median registered sale price per square foot of measured floor area. Unit: AED per sqft. Grain: building × bedroom, trailing 12 months. When null: No publishable price median, or no measured area on the records."
},
"fairPsf": {
"type": [
"number",
"null"
],
"description": "The recorded price: median price per square foot over the trailing 12 months, requiring at least five registered READY sales. medianPriceSqft and yieldPrice use the same period but pool ready and off-plan sales. Read it with fairWindowMonths and fairSaleCount; the figure is not publishable without them. Unit: AED per sqft. Grain: building x bedroom, trailing 12 months. When null: No window in the last 12 months held five ready sales. Not zero and not stale: the building has not traded enough recently for a median to mean anything."
},
"fairPrice": {
"type": [
"number",
"null"
],
"description": "Median total price over the same window as fairPsf. A median across the units that happened to trade, never an appraisal of one apartment: floor, view, condition and layout all move a real price and none is in this figure. Unit: AED. Grain: building x bedroom, same window as fairPsf. When null: As fairPsf."
},
"fairWindowMonths": {
"type": [
"integer",
"null"
],
"enum": [
3,
6,
12,
null
],
"description": "The recorded-price window: 12 months for current snapshots. Historical snapshots may carry 3 or 6. A price whose window is unstated is not evidence, so every surface prints this beside the figure. Unit: months. Grain: building x bedroom. When null: fairPsf is null."
},
"fairSaleCount": {
"type": [
"integer",
"null"
],
"description": "Registered ready sales inside the window. Never fewer than five: a price computed from two sales moves by a third when one penthouse trades. Unit: sales. Grain: building x bedroom. When null: fairPsf is null."
},
"fairAsof": {
"type": [
"string",
"null"
],
"format": "date",
"description": "Date of the most recent sale inside the window. A 12-month window whose newest sale is eleven months old is a different claim from one closing last week, and this is what separates them. Unit: date. Grain: building x bedroom. When null: fairPsf is null."
},
"launchPsf": {
"type": [
"number",
"null"
],
"description": "Median price per square foot of off-plan sales registered in the twelve months after the building's first off-plan sale: the developer's opening-year price for that unit type. Carried on the off-plan row only, and published at five or more launch sales. Unit: AED per sqft. Grain: building x bedroom. When null: Fewer than five off-plan sales in the launch year, no off-plan history, or an edition built before 2026-09."
},
"launchCount": {
"type": [
"integer",
"null"
],
"description": "Off-plan sales registered in the launch year behind launchPsf. Unit: sales. Grain: building x bedroom. When null: No off-plan history, or an edition built before 2026-09."
},
"growth12mPct": {
"type": [
"number",
"null"
],
"description": "Change in the median price per square foot, last 12 months against the 12 before. Positive is a rise. Unit: percent. Grain: building × bedroom. When null: One of the two windows has too few sales to compare. A flat market returns 0, not null."
},
"psfPrev12": {
"type": [
"number",
"null"
],
"description": "The comparison side of growth12mPct: median price per square foot over the prior 12-month window. growth12mPct = 100 × (medianPriceSqft ÷ psfPrev12 − 1). Sale rows only. Unit: AED per sqft. Grain: building × bedroom, the 12 months before the trailing 12. When null: No sales in the prior window, or an edition built before 2026-10."
},
"txnCountPrev12": {
"type": [
"integer",
"null"
],
"description": "Sales with a price per square foot behind psfPrev12. growth12mPct is published only when this and psfCount12m are both five or more, so a null growth with a count here says which side was thin. Unit: sales. Grain: building × bedroom, prior 12 months. When null: An edition built before 2026-10."
},
"psfCount12m": {
"type": [
"integer",
"null"
],
"description": "Sales with a price per square foot in the trailing 12 months. This is the current sample behind growth12mPct, appreciation3yPct and appreciation5yPct. It can be smaller than txnCount12m when some registered sales have no usable area. Sale rows only. Unit: sales. Grain: building × bedroom, trailing 12 months. When null: No such sales, a rent or off-plan row, or an edition built before the column existed."
},
"appreciation3yPct": {
"type": [
"number",
"null"
],
"description": "Change in median price per square foot, trailing 12 months against the calendar year three years before the data date (psfY3). Every building's figure covers the same span. Unit: percent. Grain: building × bedroom. When null: Fewer than five sales in the anchor year."
},
"psfY3": {
"type": [
"number",
"null"
],
"description": "Median price per square foot in the anchor year of appreciation3yPct. Unit: AED per sqft. Grain: building × bedroom, one calendar year. When null: No sales that year, or an edition built before 2026-10."
},
"txnCountY3": {
"type": [
"integer",
"null"
],
"description": "Sales behind psfY3; appreciation3yPct needs five. Unit: sales. Grain: building × bedroom, one calendar year. When null: An edition built before 2026-10."
},
"appreciation5yPct": {
"type": [
"number",
"null"
],
"description": "As appreciation3yPct, against the calendar year five years before the data date (psfY5). Unit: percent. Grain: building × bedroom. When null: Fewer than five sales in the anchor year."
},
"psfY5": {
"type": [
"number",
"null"
],
"description": "Median price per square foot in the anchor year of appreciation5yPct. Unit: AED per sqft. Grain: building × bedroom, one calendar year. When null: No sales that year, or an edition built before 2026-10."
},
"txnCountY5": {
"type": [
"integer",
"null"
],
"description": "Sales behind psfY5; appreciation5yPct needs five. Unit: sales. Grain: building × bedroom, one calendar year. When null: An edition built before 2026-10."
},
"rentGrowth12mPct": {
"type": [
"number",
"null"
],
"description": "Change in the median NEW-contract annual rent, trailing 12 months against the 12 before: 100 × (medianRent ÷ rentPrev12 − 1). Five contracts each side. Unit: percent. Grain: building × bedroom. When null: One of the two windows has fewer than five new contracts."
},
"rentPrev12": {
"type": [
"number",
"null"
],
"description": "The comparison side of rentGrowth12mPct: median new-contract annual rent over the prior 12-month window. Unit: AED per year. Grain: building × bedroom, prior 12 months. When null: No new contracts in the prior window, or an edition built before 2026-10."
},
"rentCountPrev12": {
"type": [
"integer",
"null"
],
"description": "New contracts behind rentPrev12. Unit: contracts. Grain: building × bedroom, prior 12 months. When null: An edition built before 2026-10."
},
"rentGrowth3yPct": {
"type": [
"number",
"null"
],
"description": "Change in the median new-contract rent, trailing 12 months against the calendar year three years before the data date (rentY3). Five contracts at each end from the 2026-10 edition on. Unit: percent. Grain: building × bedroom. When null: Fewer than five new contracts at either end."
},
"rentY3": {
"type": [
"number",
"null"
],
"description": "Median new-contract annual rent in the anchor year of rentGrowth3yPct. Unit: AED per year. Grain: building × bedroom, one calendar year. When null: No new contracts that year, or an edition built before 2026-10."
},
"rentCountY3": {
"type": [
"integer",
"null"
],
"description": "New contracts behind rentY3. Unit: contracts. Grain: building × bedroom, one calendar year. When null: An edition built before 2026-10."
},
"medianRent": {
"type": [
"number",
"null"
],
"description": "Median annual rent on new Ejari contracts. Registered contracts, not listing asks. Unit: AED per year. Grain: building × bedroom, trailing 12 months. When null: Too few registe
# --- truncated at 32 KB (126 KB total) ---
# Full source: https://artifacts.apis.io/dubaiwealthindex-com/openapi/_original/dubaiwealthindex-com-api-openapi.json