{
  "openapi": "3.0.1",
  "info": {
    "title": "Zumper Scraper - Rentals, Prices, Agents & 60+ Fields",
    "description": "Scrape Zumper.com rental listings: apartments, houses, condos and rooms. Pulls 60+ fields per listing, including monthly rent, beds/baths, square footage, decoded amenities, agent name and phone, ratings, availability and full-resolution photos. Search by location with filters, or paste Zumper URLs.",
    "version": "1.0",
    "x-build-id": "SdN8pGqAOEfZtlB3Q"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/abotapi~zumper-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-abotapi-zumper-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/abotapi~zumper-scraper/runs": {
      "post": {
        "operationId": "runs-sync-abotapi-zumper-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/abotapi~zumper-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-abotapi-zumper-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",
        "required": [
          "mode"
        ],
        "properties": {
          "mode": {
            "title": "Mode",
            "enum": [
              "search",
              "url"
            ],
            "type": "string",
            "description": "search = build URLs from the search fields below; url = pass through your own Zumper URLs.",
            "default": "search"
          },
          "locations": {
            "title": "Locations",
            "uniqueItems": true,
            "type": "array",
            "description": "Search mode only. City, state or neighborhood slug or name, e.g. \"San Francisco, CA\", \"new-york-ny\" or \"Austin, TX\". Leave empty to search New York, NY. A bare ZIP code is not a Zumper search page: to search one ZIP, paste its city and ZIP link (for example /apartments-for-rent/san-francisco-ca/94110) in URL mode. Multiple locations supported. Ignored in URL mode.",
            "items": {
              "type": "string"
            }
          },
          "propertyCategory": {
            "title": "Property category",
            "enum": [
              "apartments",
              "houses",
              "condos",
              "rooms"
            ],
            "type": "string",
            "description": "Search mode only for choosing which rental category to browse. In URL mode it filters nothing: the category is read from the pasted URL, and this value is used only as the label on the saved records when the pasted URL does not name a category.",
            "default": "apartments"
          },
          "petsAllowed": {
            "title": "Pets allowed",
            "uniqueItems": true,
            "type": "array",
            "description": "Search mode only. Asks Zumper for listings that allow the selected pets. It is not re-checked against the returned listings, and it has no effect in URL mode.",
            "items": {
              "type": "string",
              "enum": [
                "dogs",
                "cats"
              ],
              "enumTitles": [
                "Dogs",
                "Cats"
              ]
            }
          },
          "urls": {
            "title": "Zumper URLs",
            "uniqueItems": true,
            "type": "array",
            "description": "URL mode only. Paste Zumper search-results URLs or individual building/listing URLs. The filter and sort fields below still apply to a pasted search-results URL; a pasted building or listing URL is saved as-is. Search URLs continue from their page number onward. Supported shapes: city, category (apartments/houses/condos/rooms), paginated, filtered or sorted (price-min/max, bed-min/max, bath-min, pets, sort), neighborhood and city/ZIP search pages (the city and ZIP form, for example /apartments-for-rent/san-francisco-ca/94110), plus building or listing pages. Facets in a pasted URL win over the filter fields below.",
            "default": [
              "https://www.zumper.com/apartments-for-rent/san-francisco-ca",
              "https://www.zumper.com/houses-for-rent/austin-tx",
              "https://www.zumper.com/condos-for-rent/san-francisco-ca",
              "https://www.zumper.com/rooms-for-rent/san-francisco-ca",
              "https://www.zumper.com/apartments-for-rent/san-francisco-ca?page=2",
              "https://www.zumper.com/apartments-for-rent/san-francisco-ca?price-max=3000&bed-min=1&sort=newest",
              "https://www.zumper.com/apartments-for-rent/san-francisco-ca/soma",
              "https://www.zumper.com/apartments-for-rent/san-francisco-ca/94110",
              "https://www.zumper.com/apartment-buildings/p13179/potrero-1010-potrero-hill-san-francisco-ca",
              "https://www.zumper.com/apartment-buildings/1717500/blueground-san-francisco-soma-san-francisco-ca",
              "https://www.zumper.com/address/2050-divisadero-st-san-francisco-ca-94115-usa"
            ],
            "items": {
              "type": "string"
            }
          },
          "minPrice": {
            "title": "Minimum rent (USD/mo)",
            "minimum": 0,
            "type": "integer",
            "description": "Applies in BOTH search mode and URL mode. Keeps listings priced at or above this monthly rent. In URL mode the results of a pasted search-results URL are narrowed after they are read; a pasted building or listing URL is saved as-is."
          },
          "maxPrice": {
            "title": "Maximum rent (USD/mo)",
            "minimum": 0,
            "type": "integer",
            "description": "Applies in BOTH search mode and URL mode. Keeps listings priced at or below this monthly rent. In URL mode the results of a pasted search-results URL are narrowed after they are read; a pasted building or listing URL is saved as-is."
          },
          "minBedrooms": {
            "title": "Minimum bedrooms",
            "minimum": 0,
            "maximum": 10,
            "type": "integer",
            "description": "Applies in BOTH search mode and URL mode. Keeps listings that can offer at least this many bedrooms; 0 = studio. In URL mode the results of a pasted search-results URL are narrowed after they are read; a pasted building or listing URL is saved as-is."
          },
          "maxBedrooms": {
            "title": "Maximum bedrooms",
            "minimum": 0,
            "maximum": 10,
            "type": "integer",
            "description": "Applies in BOTH search mode and URL mode. Keeps listings that start at or below this many bedrooms. In URL mode the results of a pasted search-results URL are narrowed after they are read; a pasted building or listing URL is saved as-is."
          },
          "minBathrooms": {
            "title": "Minimum bathrooms",
            "minimum": 0,
            "maximum": 10,
            "type": "integer",
            "description": "Applies in BOTH search mode and URL mode. Keeps listings that can offer at least this many bathrooms. In URL mode the results of a pasted search-results URL are narrowed after they are read; a pasted building or listing URL is saved as-is."
          },
          "sortBy": {
            "title": "Sort by",
            "enum": [
              "default",
              "price-asc",
              "price-desc",
              "newest",
              "rating-desc"
            ],
            "type": "string",
            "description": "Applies in BOTH search mode and URL mode. Orders the listings that get saved. In URL mode the results of a pasted search-results URL are reordered after they are read; a pasted building or listing URL is saved as-is.",
            "default": "default"
          },
          "fetchDetails": {
            "title": "Fetch detail pages",
            "type": "boolean",
            "description": "Add full description, amenity groups, pet policy, parking, deposits, fees, lease terms, units / floorplans, full agent contacts and Zumper's category ratings + resident-feedback summary. The results page already returns ~70 fields including price, beds/baths, decoded amenities, agent name, phone, rating and photos, so leaving this off is faster and cheaper.",
            "default": false
          },
          "maxPages": {
            "title": "Max pages per search",
            "minimum": 0,
            "type": "integer",
            "description": "Results pages walked per location/URL. Leave empty to walk every result page (still bounded by Max listings). Pages stop early once Max listings is reached."
          },
          "maxListings": {
            "title": "Max listings (total)",
            "minimum": 0,
            "type": "integer",
            "description": "Stop after this many listings across all searches. 0 = unlimited.",
            "default": 20
          },
          "proxy": {
            "title": "Connection",
            "type": "object",
            "description": "Runs on any Apify plan. Connections are managed automatically to keep results flowing. You may also supply your own proxy URLs.",
            "default": {
              "useApifyProxy": true,
              "apifyProxyGroups": [
                "RESIDENTIAL"
              ]
            }
          },
          "resumeFromRunId": {
            "title": "Resume from a previous run (optional)",
            "type": "string",
            "description": "Paste a previous run ID or dataset ID to continue an unbounded walk across separate runs. Listings already collected there (matched by id) are skipped, so this run only saves the new ones. Leave empty for a normal fresh run. This continues ONE specific interrupted run; for recurring monitoring of the same search, use Incremental mode below instead."
          },
          "incrementalMode": {
            "title": "Incremental changes for scheduled runs",
            "type": "boolean",
            "description": "Turn this on for daily/weekly or other recurring monitoring of the SAME search. The first run returns every matching listing as NEW. Later runs normally return only NEW, UPDATED, and REAPPEARED listings. UPDATED means any output field changed (rent and previous rent, availability date, beds, baths, size, amenities, description, photos, fees, specials, units) except scrapedAt and the fields you list in Ignore fields; the changed fields are named in changedFields. Order of the amenity lists never counts. Reviews are not part of this record. Turn on \"Emit unchanged\" or \"Emit expired\" only when you also want those returned (and billed). State is kept separately per location/category/filter/fetchDetails setup; use State key to name or deliberately share a monitoring campaign. Defaults off, so existing schedules are unaffected. To continue one specific interrupted run instead, use Resume from a previous run above.",
            "default": false
          },
          "stateKey": {
            "title": "State key (optional, incremental mode only)",
            "type": "string",
            "description": "Optional. Name this monitoring campaign to keep its state stable, or to deliberately share state across differently-configured runs. Leave empty to let the actor derive a key automatically from the location/category/filters/fetchDetails, so different searches then never mix state with each other."
          },
          "emitUnchanged": {
            "title": "Emit unchanged listings (incremental mode only)",
            "type": "boolean",
            "description": "Off by default. Turn on to also return listings that have not changed since the last run, marked UNCHANGED. This returns (and bills) extra rows you already have, so leave it off unless you specifically want the full snapshot every run.",
            "default": false
          },
          "emitExpired": {
            "title": "Emit expired listings (incremental mode only)",
            "type": "boolean",
            "description": "Off by default. Turn on to also return listings that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search, not when Max pages/Max listings capped it or when Resume was used. This returns (and bills) extra synthetic rows, so leave it off unless you need expiry tracking.",
            "default": false
          },
          "expireAfterMissedScans": {
            "title": "Expire after missed scans (incremental mode only)",
            "minimum": 1,
            "type": "integer",
            "description": "With Emit expired on, a listing is reported EXPIRED only after it was missing from this many CONSECUTIVE complete scans of the same search (default 1 = the first complete scan that misses it). A listing that comes back resets the count. EXPIRED means the listing dropped out of the search results; without a detail check a dropped listing and a delisted one look the same, so use dateAvailable and the price fields rather than reading EXPIRED as unavailable.",
            "default": 1
          },
          "changeScope": {
            "title": "Change scope (incremental mode only)",
            "enum": [
              "all",
              "priceAndStock"
            ],
            "type": "string",
            "description": "all (default) compares every output field except the ones excluded below. priceAndStock compares ONLY the rent fields (minPrice, maxPrice, previousPrice, averagePrice, currency), dateAvailable, and for units / floorplanListings each element's id plus its price and availability keys, so description, photo, amenity or agent edits never create a billable UPDATED row. Changing scope on an explicit State key does not re-report existing listings; an automatic key is unaffected.",
            "default": "all"
          },
          "compactUpdates": {
            "title": "Compact UPDATED and EXPIRED rows (incremental mode only)",
            "type": "boolean",
            "description": "Return UPDATED and EXPIRED rows as slim records: id, url, title, address, current price and availability, changedFields, priceChanges (old and new per field) and variantChanges (per unit ADDED, REMOVED or CHANGED). NEW rows stay full. Compact rows carry no detail-page data, so they never add the detail enrichment charge. Default off.",
            "default": false
          },
          "ignoreFieldsForChanges": {
            "title": "Ignore fields when detecting changes (incremental mode only)",
            "type": "array",
            "description": "Field names (dotted paths reach inside objects and every array element, for example units.status) that must NOT count as a change. The fields stay in the output; they are only left out of the comparison and out of changedFields. scrapedAt is always ignored. Existing saved state is re-compared under this list, so adding a field never reports every listing as UPDATED.",
            "default": [],
            "items": {
              "type": "string"
            }
          },
          "mcpConnectors": {
            "title": "Pipe results into your apps (optional)",
            "type": "array",
            "description": "Optionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify Settings, then select it here. The connector receives a condensed, human-readable summary per item (title + key fields), not the full JSON; the complete record stays in the dataset. Leave empty to skip. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com)."
          },
          "notionParentPageUrl": {
            "title": "Notion parent page (Notion connector only)",
            "type": "string",
            "description": "URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors."
          },
          "maxNotifyListings": {
            "title": "Max items to export per connector",
            "minimum": 1,
            "maximum": 1000,
            "type": "integer",
            "description": "Cap on items written to each connector per run. Does not affect the dataset.",
            "default": 50
          }
        }
      },
      "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
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "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
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}