> ## Documentation Index
> Fetch the complete documentation index at: https://qwady.wiki/llms.txt
> Use this file to discover all available pages before exploring further.

# Batch Lookup

> Resolve many listing IDs in a single request (up to your tier's `perPage`
cap). Serves cached data only — it never triggers a live fetch — and is
billed at one request unit per requested (deduped) ID. `amenities` and
`internetProviders` are omitted from batch results; use
`GET /property/{id}` when you need those.

**Tier:** Starter+




## OpenAPI

````yaml POST /property/batch
openapi: 3.1.0
info:
  title: Borough API
  description: >
    NYC Real Estate Data API: structured access to rental and sale listings,

    building details, neighborhood data, and market statistics.


    ## Authentication


    All authenticated endpoints require a `Bearer` token in the `Authorization`
    header:

    ```

    Authorization: Bearer BOROUGH-<your-license-key>

    ```


    License keys are provisioned automatically when you subscribe via

    [Polar.sh](https://polar.sh/qwady-solutions-llc/portal). Free-tier endpoints

    (search, areas, market, and photos) work without authentication but are
    tracked per IP and subject to

    IP-based rate limits of 10 requests per minute. The health check endpoint
    remains fully public.


    ## Rate Limits


    | Tier     | Requests/min | Requests/month | Max perPage |

    |----------|-------------|----------------|-------------|

    | Free     | 10          | 100            | 10          |

    | Starter  | 30          | 5,000          | 50          |

    | Pro      | 60          | 25,000         | 500         |

    | Business | 120         | 100,000        | 500         |


    Tiered API responses include the `X-RateLimit-Limit` and `X-Quota-*`
    headers,

    plus an `X-Request-Id` header (UUID v4) for request tracing and debugging.

    Note that 429 responses additionally carry a `Retry-After` header and an

    `error.retryAfter` value in the body. The health check remains fully public

    and does not carry quota headers.


    ## Data Freshness


    Freshness-aware JSON data responses include a `meta.dataAge` field (ISO

    8601) indicating when the underlying data was last scraped, and a

    `meta.source` field indicating how the data was served (`cached`, `stale`,

    or `live`).


    Public cache cadence varies by dataset: rental search refreshes every 6h,

    sale search every 8h, listing detail sweeps every 12h, buildings every 3

    days, broadband enrichment monthly, and market snapshots daily at 05:00 UTC.

    Paid tiers use freshness thresholds to trigger background refreshes when

    cached data exceeds the threshold for that route family.


    | Tier     | Search Threshold | Listing Threshold | Building Threshold |

    |----------|------------------|-------------------|--------------------|

    | Starter  | 8h               | 30min             | 6h                 |

    | Pro      | 8h               | 15min             | 3h                 |

    | Business | 8h               | 10min             | 2h                 |


    ## Photo URLs


    Listing and building responses include photo keys (32-character hex hashes).

    Use the Borough proxy for first-party image URLs:

    ```

    https://borough.qwady.app/v1/photos/{key}

    ```

    Supported sizes:

    ```

    large_800_400 (default), medium_500_250

    ```
  version: 1.0.0
  contact:
    name: Qwady Solutions LLC
    url: https://borough.qwady.app
    email: api@qwady.com
  license:
    name: Proprietary
    url: https://borough.qwady.app/terms
servers:
  - url: https://borough.qwady.app/v1
    description: Production
security:
  - BearerAuth: []
tags:
  - name: Search
    description: Search rental and sale listings with filters
  - name: Property
    description: Individual listing details and price history
  - name: Building
    description: Building information, amenities, and active listings
  - name: Areas
    description: Neighborhoods, boroughs, and geographic boundaries
  - name: Market
    description: Market snapshots, trends, and area comparisons
  - name: Webhooks
    description: Webhook subscriptions for listing change notifications
  - name: Watchers
    description: Persistent watchers for real-time listing, building, and search monitoring
  - name: Streaming
    description: Server-Sent Events for live data and watcher changes
  - name: Utility
    description: Health checks and internal endpoints
paths:
  /property/batch:
    post:
      tags:
        - Property
      summary: Batch listing lookup
      description: >
        Resolve many listing IDs in a single request (up to your tier's
        `perPage`

        cap). Serves cached data only — it never triggers a live fetch — and is

        billed at one request unit per requested (deduped) ID. `amenities` and

        `internetProviders` are omitted from batch results; use

        `GET /property/{id}` when you need those.


        **Tier:** Starter+
      operationId: batchGetProperties
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - ids
              properties:
                ids:
                  type: array
                  minItems: 1
                  items:
                    type: string
                  example:
                    - '4961849'
                    - '1763374'
      responses:
        '200':
          description: Listing details for the IDs that resolved, plus the misses
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/ListingDetail'
                  meta:
                    type: object
                    properties:
                      total:
                        type: integer
                      requested:
                        type: integer
                      found:
                        type: integer
                      notFound:
                        type: array
                        items:
                          type: string
                      dataAge:
                        type:
                          - string
                          - 'null'
                        format: date-time
                      source:
                        type: string
                        example: cached
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/TierRestricted'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalError'
components:
  schemas:
    ListingDetail:
      allOf:
        - $ref: '#/components/schemas/ListingSummary'
        - type: object
          properties:
            sqft:
              type:
                - integer
                - 'null'
            saleType:
              oneOf:
                - type: string
                  enum:
                    - RESALE
                    - SPONSOR_UNIT
                    - FORECLOSURE
                - type: 'null'
            noFee:
              type: boolean
            petsAllowed:
              type:
                - boolean
                - 'null'
            amenities:
              type:
                - array
                - 'null'
              items:
                type: string
            furnished:
              type: boolean
            availableAt:
              type:
                - string
                - 'null'
              format: date
            listedAt:
              type:
                - string
                - 'null'
              format: date
            daysOnMarket:
              type:
                - integer
                - 'null'
            floorPlanKey:
              type:
                - string
                - 'null'
            has3dTour:
              type: boolean
            hasVideo:
              type: boolean
            buildingId:
              type:
                - string
                - 'null'
            priceDelta:
              type:
                - integer
                - 'null'
            priceChangedAt:
              type:
                - string
                - 'null'
              format: date-time
            detailScraped:
              type: boolean
            maintenance:
              type:
                - integer
                - 'null'
            commonCharges:
              type:
                - integer
                - 'null'
            propertyTax:
              type:
                - integer
                - 'null'
            virtualTourUrl:
              type:
                - string
                - 'null'
            internetProviders:
              oneOf:
                - $ref: '#/components/schemas/InternetProviders'
                - type: 'null'
    ListingSummary:
      type: object
      properties:
        id:
          type: string
        address:
          $ref: '#/components/schemas/Address'
        price:
          type: integer
        netEffective:
          type:
            - integer
            - 'null'
        monthsFree:
          type:
            - integer
            - 'null'
        leaseTermMonths:
          type:
            - integer
            - 'null'
        bedroomCount:
          type:
            - integer
            - 'null'
        fullBathroomCount:
          type:
            - integer
            - 'null'
        halfBathroomCount:
          type:
            - integer
            - 'null'
        sqft:
          description: >-
            Interior square footage. Populated only on detail-scraped listings;
            null otherwise.
          type:
            - integer
            - 'null'
        pricePerSqft:
          description: >-
            Price divided by sqft, rounded to the nearest dollar. Null when sqft
            is unavailable.
          type:
            - integer
            - 'null'
        buildingType:
          oneOf:
            - type: string
              enum:
                - CONDO
                - CO_OP
                - RENTAL
                - TOWNHOUSE
                - MULTI_FAMILY
                - HOUSE
                - TWOFAMILY
                - THREEFAMILY
                - MIXED_USE
            - type: 'null'
        areaName:
          type:
            - string
            - 'null'
        areaId:
          type:
            - integer
            - 'null'
        status:
          type: string
          enum:
            - ACTIVE
            - IN_CONTRACT
            - OFF_MARKET
          description: >-
            Borough currently emits ACTIVE and OFF_MARKET only. IN_CONTRACT is a
            reserved, forward-compatible value not yet surfaced by the data
            feed.
        geoPoint:
          oneOf:
            - $ref: '#/components/schemas/GeoPoint'
            - type: 'null'
        leadPhotoKey:
          type:
            - string
            - 'null'
          description: '32-char hex key. Preferred first-party URL: `/v1/photos/{key}`.'
        sourceGroupLabel:
          type:
            - string
            - 'null'
          description: Brokerage name
        urlPath:
          type: string
        listingType:
          type: string
          enum:
            - rental
            - sale
        listedAt:
          type:
            - string
            - 'null'
          format: date
          description: >-
            Date the listing went on market (YYYY-MM-DD). For listings not yet
            detail-scraped this is the date Borough first observed the listing,
            accurate to within one feed cycle. See listedAtIsApproximate.
        listedAtIsApproximate:
          type: boolean
          description: >-
            True when listedAt is the feed-first-seen estimate (the listing has
            not yet been detail-scraped), false when it is the authoritative
            on-market date from the listing detail page. daysOnMarket inherits
            this accuracy, so use the flag before relying on listedAt /
            daysOnMarket for date filtering or time-on-market analysis.
        availableAt:
          type:
            - string
            - 'null'
          format: date
        daysOnMarket:
          type:
            - integer
            - 'null'
          description: >-
            Derived from listedAt; null when listedAt is unknown. Carries the
            same accuracy as listedAt (see listedAtIsApproximate).
    InternetProviders:
      type: object
      description: >-
        FCC-backed internet availability block. Coverage may be exact-building
        when Borough has a matched FCC location, or Census-block level when
        sourced from the official FCC Broadband Data Collection public bulk
        files.
      properties:
        status:
          type: string
          enum:
            - matched
            - unmatched
            - error
        source:
          type: string
          enum:
            - fcc_bdc
        coverageLevel:
          type: string
          enum:
            - building
            - census_block
        fccLocationId:
          description: >-
            Matched FCC location identifier when exact-building matching is
            available. Null for Census-block bulk imports.
          type:
            - integer
            - 'null'
        blockGeoid:
          description: Census block GEOID for Census-block bulk imports, when available.
          type:
            - string
            - 'null'
        matchedAddress:
          type:
            - string
            - 'null'
        unitCount:
          type:
            - integer
            - 'null'
        updatedAt:
          type:
            - string
            - 'null'
          format: date-time
        providers:
          type: array
          items:
            $ref: '#/components/schemas/InternetProviderOffering'
        disclaimer:
          type: string
    ErrorResponse:
      type: object
      properties:
        error:
          type: object
          required:
            - code
            - message
            - status
          properties:
            code:
              type: string
              enum:
                - INVALID_PARAMS
                - MISSING_API_KEY
                - INVALID_API_KEY
                - EXPIRED_API_KEY
                - TIER_RESTRICTED
                - QUOTA_EXCEEDED
                - NOT_FOUND
                - WEBHOOK_NOT_FOUND
                - RATE_LIMIT_EXCEEDED
                - INTERNAL_ERROR
                - UPSTREAM_ERROR
                - SERVICE_DISABLED
            message:
              type: string
            status:
              type: integer
            retryAfter:
              type:
                - integer
                - 'null'
              description: Seconds to wait before retrying (for 429 responses)
    Address:
      type: object
      properties:
        street:
          type: string
          example: 157 West 57th Street
        unit:
          type:
            - string
            - 'null'
          example: '#48B'
    GeoPoint:
      type: object
      properties:
        latitude:
          type: number
          format: double
          example: 40.7654
        longitude:
          type: number
          format: double
          example: -73.9791
    InternetProviderOffering:
      type: object
      properties:
        providerId:
          type: integer
        providerName:
          type: string
        holdingCompanyName:
          type:
            - string
            - 'null'
        technologyCode:
          type: integer
        technologyLabel:
          type: string
        maxDownloadMbps:
          type:
            - integer
            - 'null'
        maxUploadMbps:
          type:
            - integer
            - 'null'
        lowLatency:
          type:
            - boolean
            - 'null'
  responses:
    BadRequest:
      description: Invalid parameters
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: INVALID_PARAMS
              message: Parameter 'maxPrice' must be a positive integer.
              status: 400
    Unauthorized:
      description: Missing or invalid API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: INVALID_API_KEY
              message: The provided API key is invalid or expired.
              status: 401
    TierRestricted:
      description: Endpoint not available on current tier
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: TIER_RESTRICTED
              message: This endpoint requires a Pro subscription or higher.
              status: 403
    RateLimited:
      description: Rate limit exceeded
      headers:
        Retry-After:
          schema:
            type: integer
          description: Seconds until rate limit resets
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: RATE_LIMIT_EXCEEDED
              message: Rate limit exceeded. Retry after 32 seconds.
              status: 429
              retryAfter: 32
    InternalError:
      description: Unexpected server error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
          example:
            error:
              code: INTERNAL_ERROR
              message: >-
                An unexpected error occurred. Please retry or contact support
                with the X-Request-Id.
              status: 500
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: BOROUGH-<uuid>
      description: 'Polar.sh license key. Format: `BOROUGH-<uuid>`'

````