{
  "openapi": "3.0.1",
  "info": {
    "title": "Realtor.ca Scraper",
    "description": "Scrape Realtor.ca, Canada's national MLS portal. Extracts active listings with a deep schema: price, beds/baths (X+Y format), ownership type, CAD taxes & condo fees, heating/cooling, features, photos, agent contact, plus REALTOR agent & brokerage profiles. 5 modes, bilingual EN/FR.",
    "version": "0.0",
    "x-build-id": "d3dBRd7iJrHsybqJg"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/haketa~realtor-ca-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-haketa-realtor-ca-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/haketa~realtor-ca-scraper/runs": {
      "post": {
        "operationId": "runs-sync-haketa-realtor-ca-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/haketa~realtor-ca-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-haketa-realtor-ca-scraper",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "properties": {
          "mode": {
            "title": "Scrape Mode",
            "enum": [
              "search-area",
              "map-bbox",
              "single-listing",
              "agent-profile",
              "office-profile"
            ],
            "type": "string",
            "description": "'search-area' = crawl Realtor.ca province/city result pages. 'map-bbox' = search a geographic bounding box via the map API. 'single-listing' = scrape individual listing URLs. 'agent-profile' = scrape REALTOR agent profile pages. 'office-profile' = scrape brokerage/office profile pages.",
            "default": "search-area"
          },
          "searchUrls": {
            "title": "Realtor.ca URLs",
            "type": "array",
            "description": "Realtor.ca inputs. Used by every mode except 'map-bbox'. Examples — search-area: 'https://www.realtor.ca/on/ottawa/real-estate'; single-listing: an MLS number like 'X13126780' (required — listing URLs do not contain the MLS number the detail API needs); agent-profile: 'https://www.realtor.ca/agent/2182401/jane-doe'; office-profile: 'https://www.realtor.ca/office/firm/259003/royal-lepage-team'.",
            "items": {
              "type": "string"
            }
          },
          "mapBoundingBox": {
            "title": "Map Bounding Box",
            "type": "object",
            "description": "Geographic bounding box for 'map-bbox' mode. Provide latMin, latMax, lngMin, lngMax (decimal degrees). Example for central Ottawa: { \"latMin\": 45.30, \"latMax\": 45.50, \"lngMin\": -75.85, \"lngMax\": -75.55 }. Large boxes are auto-split into a grid to stay under the per-query result cap."
          },
          "transactionType": {
            "title": "Transaction Type",
            "enum": [
              "for-sale",
              "for-rent",
              "both"
            ],
            "type": "string",
            "description": "Filter by for-sale or for-rent listings.",
            "default": "for-sale"
          },
          "propertyTypeGroup": {
            "title": "Property Type Group",
            "enum": [
              "residential",
              "commercial",
              "all"
            ],
            "type": "string",
            "description": "High-level property category. 'residential' = houses, condos, townhomes. 'commercial' = office, retail, industrial, business. 'all' = no filter.",
            "default": "residential"
          },
          "priceMin": {
            "title": "Min Price (CAD)",
            "minimum": 0,
            "type": "integer",
            "description": "Minimum price in Canadian dollars. 0 = no minimum.",
            "default": 0
          },
          "priceMax": {
            "title": "Max Price (CAD)",
            "minimum": 0,
            "type": "integer",
            "description": "Maximum price in Canadian dollars. 0 = no maximum.",
            "default": 0
          },
          "bedroomsMin": {
            "title": "Min Bedrooms",
            "minimum": 0,
            "type": "integer",
            "description": "Minimum bedroom count. 0 = no minimum.",
            "default": 0
          },
          "bathroomsMin": {
            "title": "Min Bathrooms",
            "minimum": 0,
            "type": "integer",
            "description": "Minimum bathroom count. 0 = no minimum.",
            "default": 0
          },
          "newListingsOnlyDays": {
            "title": "New Listings Only (last N days)",
            "minimum": 0,
            "type": "integer",
            "description": "Keep only listings first published within the last N days (based on listing date). 0 = keep all.",
            "default": 0
          },
          "language": {
            "title": "Language Filter",
            "enum": [
              "both",
              "en",
              "fr"
            ],
            "type": "string",
            "description": "Filter listings by detected description language. 'both' keeps EN and FR. Quebec listings are typically French.",
            "default": "both"
          },
          "fetchDetails": {
            "title": "Fetch Full Listing Details",
            "type": "boolean",
            "description": "Visit each listing's detail page for the complete record — full remarks, all photos, features, appliances, heating/cooling, basement, financials. Slower but much richer. When false, only search-result summary fields are extracted.",
            "default": true
          },
          "fetchAgentProfiles": {
            "title": "Enrich With Agent Profiles",
            "type": "boolean",
            "description": "For listing modes, additionally fetch the full REALTOR agent profile (bio, designations, languages, service areas, listing counts) for each listing's agent. Adds one request per unique agent.",
            "default": false
          },
          "fetchOfficeProfiles": {
            "title": "Enrich With Office Profiles",
            "type": "boolean",
            "description": "For listing modes, additionally fetch the brokerage/office profile (franchise, agent count, total listings) for each listing's office. Adds one request per unique office.",
            "default": false
          },
          "maxItems": {
            "title": "Max Items",
            "minimum": 0,
            "type": "integer",
            "description": "Maximum total records to scrape across all inputs. Set 0 for unlimited.",
            "default": 100
          },
          "maxPages": {
            "title": "Max Pages per Search",
            "minimum": 0,
            "type": "integer",
            "description": "Maximum result pages per search area / bounding box. Each page returns up to ~200 listings via the API.",
            "default": 10
          },
          "proxyConfiguration": {
            "title": "Proxy Configuration",
            "type": "object",
            "description": "REQUIRED. Realtor.ca has aggressive anti-bot (reCAPTCHA, token gating). Use Apify Proxy with the RESIDENTIAL group and CA country — datacenter IPs are blocked quickly."
          },
          "requestDelay": {
            "title": "Request Delay (ms)",
            "minimum": 0,
            "maximum": 30000,
            "type": "integer",
            "description": "Delay between requests in milliseconds. Realtor.ca rate-limits aggressively — keep this at 1000+ for sustained runs.",
            "default": 1500
          },
          "maxConcurrency": {
            "title": "Max Concurrency",
            "minimum": 1,
            "maximum": 8,
            "type": "integer",
            "description": "Parallel requests. Realtor.ca tolerates only 2-4 — keep low to avoid blocks.",
            "default": 2
          },
          "maxRetries": {
            "title": "Max Retries",
            "minimum": 0,
            "maximum": 10,
            "type": "integer",
            "description": "Retry attempts per failed request (403/429/503/captcha responses).",
            "default": 4
          },
          "applicationId": {
            "title": "API Application ID (advanced)",
            "type": "string",
            "description": "Advanced: the ApplicationId value sent to the api2.realtor.ca search API. Leave empty to use the default. Only change this if the API stops returning results and you have a known-good value.",
            "default": ""
          },
          "debugMode": {
            "title": "Debug Mode",
            "type": "boolean",
            "description": "Verbose logging — dumps API request/response structure, HTML hydration shape, raw listing keys and field maps for the first page of each input. Use for troubleshooting when Realtor.ca changes its structure. Leave off for normal runs.",
            "default": false
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}