PropertyIndex Market index API

Monthly PIX index levels and supporting observations by segment.

GitHub OpenAPI

Operations 1

GET /v1/market-index List observations #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/propertyindex-ae:propertyindex-ae-market-index-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

propertyindex-ae-market-index-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: PIX Market index API
  version: 1.0.0
  description: 'The PIX API gives licensed organisations direct, programmatic access to the

    Dubai Land Department records that PropertyIndex models: every registered

    sale, every registered tenancy period, its location labels and floor,

    and the PIX market index, as flat rows you can pull into your

    own systems. Each record carries its registered figures and our per-record

    calculations (price and rent per square foot, normalised property type and

    bedrooms). Location and floor labels are not identifiers or proof of a

    unique physical structure. Unit numbers, persistent property identities and cross-record histories are

    not part of the API. ## Location labels


    Sales and rentals carry the record''s assigned location as labels:


    - `location_path` is the full published path, an ordered list of labels

    from Dubai to the assigned location. - `highest_location_level` is the first node after Dubai, regardless of

    its kind. - `lowest_location_level` is the final assigned location node, which

    may be an area, community, subcommunity, tower or the city itself. For a sale in Beach Vista Tower 1:


    ```json

    {

    "location_path": ["Dubai", "Dubai Harbour", "Emaar Beachfront", "Beach Vista", "Beach Vista Tower 1"],

    "highest_location_level": "Dubai Harbour",

    "lowest_location_level": "Beach Vista Tower 1"

    }

    ```


    When only one node follows Dubai, both level fields contain that node''s

    label. For a city-only assignment, the path is `["Dubai"]`, the highest

    value is null and the lowest is `Dubai`. All three are null when the

    location is unresolved; a path is never partial. Labels are names, not identifiers, and names can repeat across the tree. `location_path` is returned by default and can be requested with

    `fields`, but it is not a filter, sort or cursor field. To scope a query

    to a place, use `location_id`. ## Base URL


    All endpoints are served from `https://api.propertyindex.ae`. Only `GET`

    requests are accepted. Responses are JSON. ## Authentication


    Send your key as a bearer token on every request:


    ```

    Authorization: Bearer pix_api_XXXXXXXXXX_... ```


    Keys are issued to your organisation, not to a person. Keep them server-side. A key can be revoked and reissued at any time on request. ## Allowance and rate limits


    Authenticated responses carry your meter in headers: `PIX-Usage-Used`,

    `PIX-Usage-Allowance`, `PIX-Usage-Remaining`, `PIX-Usage-Period` and,

    where the period has an end, `PIX-Usage-Period-End`. `PIX-Usage-Unit: records` identifies the unit. `PIX-Usage-Remaining`

    means included records remaining, excluding optional overage capacity. `GET /v1/usage` returns these figures and the effective

    `recordsRemaining`, including any enabled overage capacity, without

    consuming records. The paid plan is AED 5,000 per month and includes 1,000,000 sales and rental

    records per billing period, shared across the organisation''s API keys. Each actual row returned by a sales or rentals

    list counts as one record; a successful single-record response counts as

    one. Repeated retrievals count again. Query and validation failures and

    empty responses consume no records. Locations, market index, documentation

    and usage are unmetered. Optional overage costs AED 2 per 1,000 records, prorated to the nearest fils

    on the billing period total: `overageCostMinor = round(overageRecords / 5)`. Overage is off by default. An organisation owner or admin must opt in and

    set a finite monthly overage spending cap, excluding the subscription and

    any applicable taxes. `overageCapMinor` is that cap

    in fils; when enabled, each fils adds five records to `recordLimit` above

    the included allowance. `remaining` counts only unused included records;

    `recordsRemaining` counts capacity up to the effective `recordLimit`. Demo grants have a fixed record allowance with no overage. Both demo and paid keys enforce a hard limit. If the actual response would

    exceed `recordsRemaining`, the whole response is rejected with

    `429 allowance_exhausted` and no records are charged.'
  contact:
    name: PropertyIndex
    email: info@propertyindex.ae
    url: https://www.propertyindex.ae
  termsOfService: https://www.propertyindex.ae/terms-of-service
  license:
    name: PIX API licence (proprietary)
    url: https://www.propertyindex.ae/terms-of-service
servers:
- url: https://api.propertyindex.ae
security:
- bearerAuth: []
tags:
- name: Market index
  description: Monthly PIX index levels and supporting observations by segment.
paths:
  /v1/market-index:
    get:
      tags:
      - Market index
      operationId: listMarketIndexObservations
      summary: List observations
      description: 'Monthly PIX index levels by segment. Monthly PropertyIndex (PIX) levels and supporting Dubai market observations. Unmetered: consumes no records. The burst rate limit still applies.'
      parameters:
      - name: sort
        in: query
        description: Field to sort by. Default segment.
        required: false
        schema:
          type: string
          enum:
          - segment
          - month
          - index_level
          - mom_pct
          - yoy_pct
          - median_psf
          - sales_count
      - name: order
        in: query
        description: Sort direction. Default asc.
        required: false
        schema:
          type: string
          enum:
          - asc
          - desc
      - name: limit
        in: query
        description: Rows per page, 1 to 1,000. Default 100.
        required: false
        schema:
          type: integer
          minimum: 1
          maximum: 1000
      - name: page
        in: query
        description: Numbered page, starting at 1. Send one positive integer. Uses limit (default 100, maximum 1000). Cannot be combined with cursor. Omit both to start at the first page. The computed offset (page - 1) * limit must also be a safe integer. Large page numbers may be slower because earlier rows must be skipped; prefer cursors for sequential bulk walks.
        required: false
        schema:
          type: integer
          minimum: 1
          maximum: 9007199254740991
      - name: cursor
        in: query
        description: Opaque cursor from a previous response's next_cursor. Send the same sort, order and filters, including location_id and location_search where supported. Cannot be combined with page. To continue a numbered page using next_cursor, remove page.
        required: false
        schema:
          type: string
      - name: fields
        in: query
        description: Comma-separated list of fields to return. Default all.
        required: false
        schema:
          type: string
          example: segment,month
      - name: segment
        in: query
        description: Exact match on segment. Repeat the parameter to match any of several values.
        required: false
        schema:
          type: array
          items:
            type: string
            enum:
            - residential
            - apartment
            - villa
            - ready
            - offplan
        style: form
        explode: true
      - name: segment_not
        in: query
        description: Exclude rows where segment equals this value.
        required: false
        schema:
          type: string
          enum:
          - residential
          - apartment
          - villa
          - ready
          - offplan
      - name: segment_null
        in: query
        description: true keeps only rows with no segment; false keeps only rows with one.
        required: false
        schema:
          type: boolean
      - name: month
        in: query
        description: Exact match on month. Repeat the parameter to match any of several values.
        required: false
        schema:
          type: array
          items:
            type: string
            format: date
            example: '2026-01-01'
        style: form
        explode: true
      - name: month_not
        in: query
        description: Exclude rows where month equals this value.
        required: false
        schema:
          type: string
          format: date
          example: '2026-01-01'
      - name: month_null
        in: query
        description: true keeps only rows with no month; false keeps only rows with one.
        required: false
        schema:
          type: boolean
      - name: month_from
        in: query
        description: month on or after this date.
        required: false
        schema:
          type: string
          format: date
          example: '2026-01-01'
      - name: month_to
        in: query
        description: month on or before this date.
        required: false
        schema:
          type: string
          format: date
          example: '2026-01-01'
      - name: index_level
        in: query
        description: Exact match on index_level. Repeat the parameter to match any of several values.
        required: false
        schema:
          type: array
          items:
            type: number
        style: form
        explode: true
      - name: index_level_not
        in: query
        description: Exclude rows where index_level equals this value.
        required: false
        schema:
          type: number
      - name: index_level_null
        in: query
        description: true keeps only rows with no index_level; false keeps only rows with one.
        required: false
        schema:
          type: boolean
      - name: index_level_min
        in: query
        description: index_level greater than or equal to.
        required: false
        schema:
          type: number
      - name: index_level_max
        in: query
        description: index_level less than or equal to.
        required: false
        schema:
          type: number
      - name: mom_pct
        in: query
        description: Exact match on mom_pct. Repeat the parameter to match any of several values.
        required: false
        schema:
          type: array
          items:
            type: number
        style: form
        explode: true
      - name: mom_pct_not
        in: query
        description: Exclude rows where mom_pct equals this value.
        required: false
        schema:
          type: number
      - name: mom_pct_null
        in: query
        description: true keeps only rows with no mom_pct; false keeps only rows with one.
        required: false
        schema:
          type: boolean
      - name: mom_pct_min
        in: query
        description: mom_pct greater than or equal to.
        required: false
        schema:
          type: number
      - name: mom_pct_max
        in: query
        description: mom_pct less than or equal to.
        required: false
        schema:
          type: number
      - name: yoy_pct
        in: query
        description: Exact match on yoy_pct. Repeat the parameter to match any of several values.
        required: false
        schema:
          type: array
          items:
            type: number
        style: form
        explode: true
      - name: yoy_pct_not
        in: query
        description: Exclude rows where yoy_pct equals this value.
        required: false
        schema:
          type: number
      - name: yoy_pct_null
        in: query
        description: true keeps only rows with no yoy_pct; false keeps only rows with one.
        required: false
        schema:
          type: boolean
      - name: yoy_pct_min
        in: query
        description: yoy_pct greater than or equal to.
        required: false
        schema:
          type: number
      - name: yoy_pct_max
        in: query
        description: yoy_pct less than or equal to.
        required: false
        schema:
          type: number
      - name: median_psf
        in: query
        description: Exact match on median_psf. Repeat the parameter to match any of several values.
        required: false
        schema:
          type: array
          items:
            type: number
        style: form
        explode: true
      - name: median_psf_not
        in: query
        description: Exclude rows where median_psf equals this value.
        required: false
        schema:
          type: number
      - name: median_psf_null
        in: query
        description: true keeps only rows with no median_psf; false keeps only rows with one.
        required: false
        schema:
          type: boolean
      - name: median_psf_min
        in: query
        description: median_psf greater than or equal to.
        required: false
        schema:
          type: number
      - name: median_psf_max
        in: query
        description: median_psf less than or equal to.
        required: false
        schema:
          type: number
      - name: sales_count
        in: query
        description: Exact match on sales_count. Repeat the parameter to match any of several values.
        required: false
        schema:
          type: array
          items:
            type: number
        style: form
        explode: true
      - name: sales_count_not
        in: query
        description: Exclude rows where sales_count equals this value.
        required: false
        schema:
          type: number
      - name: sales_count_null
        in: query
        description: true keeps only rows with no sales_count; false keeps only rows with one.
        required: false
        schema:
          type: boolean
      - name: sales_count_min
        in: query
        description: sales_count greater than or equal to.
        required: false
        schema:
          type: number
      - name: sales_count_max
        in: query
        description: sales_count less than or equal to.
        required: false
        schema:
          type: number
      responses:
        '200':
          description: One page of rows.
          headers:
            PIX-Usage-Kind:
              description: paid or demo.
              schema:
                type: string
                enum:
                - paid
                - demo
            PIX-Usage-Unit:
              description: The usage unit is records.
              schema:
                type: string
                const: records
            PIX-Usage-Used:
              description: Sales and rental records used in the current period, including this response.
              schema:
                type: integer
                minimum: 0
            PIX-Usage-Allowance:
              description: Records included in the current period, before optional overage.
              schema:
                type: integer
                minimum: 0
            PIX-Usage-Remaining:
              description: Included records remaining, excluding overage capacity. GET /v1/usage returns recordsRemaining for effective capacity.
              schema:
                type: integer
                minimum: 0
            PIX-Usage-Period:
              description: Identifier of the current period.
              schema:
                type: string
            PIX-Usage-Period-End:
              description: When the current period ends, if it does.
              schema:
                type: string
                format: date-time
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MarketIndexObservationList'
        '400':
          description: The request is not valid. The message names the parameter.
          headers: {}
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Missing or unrecognised API key.
          headers: {}
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: The key is not active, or the organisation holds no licence or demo allowance.
          headers: {}
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: Rate limit reached, or the response exceeds recordsRemaining (allowance_exhausted). The whole response is rejected without consuming records; request a smaller limit if capacity remains.
          headers:
            PIX-Usage-Kind:
              description: paid or demo.
              schema:
                type: string
                enum:
                - paid
                - demo
            PIX-Usage-Unit:
              description: The usage unit is records.
              schema:
                type: string
                const: records
            PIX-Usage-Used:
              description: Sales and rental records used in the current period, including this response.
              schema:
                type: integer
                minimum: 0
            PIX-Usage-Allowance:
              description: Records included in the current period, before optional overage.
              schema:
                type: integer
                minimum: 0
            PIX-Usage-Remaining:
              description: Included records remaining, excluding overage capacity. GET /v1/usage returns recordsRemaining for effective capacity.
              schema:
                type: integer
                minimum: 0
            PIX-Usage-Period:
              description: Identifier of the current period.
              schema:
                type: string
            PIX-Usage-Period-End:
              description: When the current period ends, if it does.
              schema:
                type: string
                format: date-time
            Retry-After:
              description: Seconds to wait before retrying (rate limit only).
              schema:
                type: integer
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    Error:
      type: object
      required:
      - error
      properties:
        error:
          type: object
          required:
          - code
          - message
          properties:
            code:
              type: string
              example: invalid_parameter
            message:
              type: string
    MarketIndexObservation:
      type: object
      description: Monthly PropertyIndex (PIX) levels and supporting Dubai market observations.
      properties:
        segment:
          type:
          - string
          - 'null'
          description: 'PIX market segment. Known values: residential, apartment, villa, ready, offplan.'
        month:
          type:
          - string
          - 'null'
          format: date
          description: Index observation month.
        index_level:
          type:
          - number
          - 'null'
          description: 'PIX index level for the segment and month. Unit: index points.'
        mom_pct:
          type:
          - number
          - 'null'
          description: 'Month-on-month PIX change. Unit: percent.'
        yoy_pct:
          type:
          - number
          - 'null'
          description: 'Year-on-year PIX change. Unit: percent.'
        median_psf:
          type:
          - number
          - 'null'
          description: 'Observed median registered sale PSF. Unit: AED/sqft.'
        sales_count:
          type:
          - number
          - 'null'
          description: 'Registered sales supporting the observation. Unit: sales.'
    MarketIndexObservationList:
      type: object
      required:
      - data
      - next_cursor
      - as_of
      - total
      - page
      - limit
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/MarketIndexObservation'
        next_cursor:
          type:
          - string
          - 'null'
          description: Returned for cursor and numbered pages when more data exists. Pass as cursor to fetch the next page, removing page and preserving sort, order and filters. null on the last page.
        as_of:
          type:
          - string
          - 'null'
          format: date
          description: The DLD delivery date the data was built from.
        total:
          type: integer
          minimum: 0
          description: 'Exact number of records matching all filters, including q, location_search and location scopes where supported. Ignores page, limit and cursor. Always included, even on empty pages. Not a snapshot: can change after a data refresh.'
        page:
          type:
          - integer
          - 'null'
          minimum: 1
          maximum: 9007199254740991
          description: Requested numbered page, or 1 when neither page nor cursor was supplied. null for cursor requests because a cursor position is not a numbered page.
        limit:
          type: integer
          minimum: 1
          maximum: 1000
          description: Requested page size, or 100 when omitted. This is the maximum rows requested, not the actual number returned; data can contain fewer rows.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: 'Your PIX API key, sent as `Authorization: Bearer pix_api_...`.'