{
  "openapi": "3.0.1",
  "info": {
    "title": "PAP.fr Scraper - France Properties, Prices & Listings",
    "description": "Scrape PAP.fr real estate listings across France. Extract property prices, addresses, room counts, floor areas, full photo galleries, descriptions and location details including arrondissement, department and region. Ideal for property research, price comparison and market analysis.",
    "version": "1.0",
    "x-build-id": "egt4AWJzOp1b8i9CG"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/abotapi~pap-fr-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-abotapi-pap-fr-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~pap-fr-scraper/runs": {
      "post": {
        "operationId": "runs-sync-abotapi-pap-fr-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~pap-fr-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-abotapi-pap-fr-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": "1. Search mode",
            "enum": [
              "filter",
              "url"
            ],
            "type": "string",
            "description": "Filter mode = pick property type + city, plus optional price / surface / land / rooms / bedrooms / feature filters. URL mode = paste any pap.fr search or listing URL already refined in a browser.",
            "default": "filter"
          },
          "locations": {
            "title": "Locations to search (Filter mode)",
            "type": "array",
            "description": "Type a French city, town or district name as you would on pap.fr (e.g. Paris, Lyon, Paris 15e, Saint-Malo). It is looked up in pap.fr's own location search, so no site id is needed. The department code is auto-derived and only needed to pick between places that share a name (e.g. Saint-Denis exists in both 93 and 974); the run log names the alternatives when a name is ambiguous, and a name pap.fr does not know is reported with its suggestions, never guessed.",
            "items": {
              "type": "object",
              "properties": {
                "city": {
                  "title": "City",
                  "type": "string",
                  "description": "French city name, e.g. Paris, Lyon, Marseille, Bordeaux, Nice, Toulouse.",
                  "editor": "textfield"
                },
                "department": {
                  "title": "Department code (optional)",
                  "type": "string",
                  "description": "Optional. 2-digit French department code (département). Auto-derived from the city if left blank. Provide it only when the city name is shared by multiple communes (e.g. Saint-Denis: 93 vs 974, Saint-Pierre: 9 communes). Paris=75, Rhône=69, Bouches-du-Rhône=13, Gironde=33, Alpes-Maritimes=06, Haute-Garonne=31, Nord=59.",
                  "editor": "textfield"
                }
              }
            }
          },
          "listingType": {
            "title": "Buy or rent? (Filter mode)",
            "enum": [
              "Buy",
              "Rent"
            ],
            "type": "string",
            "description": "Pick Vente (Buy) or Location (Rent). Filter mode only.",
            "default": "Buy"
          },
          "listingTypes": {
            "title": "Buy and rent in one run (Filter mode)",
            "type": "array",
            "description": "Optional. Tick both to search sales AND rentals for every location in the same run (each listing keeps its own Buy/Rent label). When set, this replaces \"Buy or rent?\". Leave empty to use \"Buy or rent?\" alone. Filter mode only.",
            "items": {
              "type": "string",
              "enum": [
                "Buy",
                "Rent"
              ],
              "enumTitles": [
                "Vente / Buy",
                "Location / Rent"
              ]
            }
          },
          "propertyType": {
            "title": "Property type (Filter mode)",
            "enum": [
              "Apartment",
              "House",
              "Plot",
              "Parking",
              "CommercialProperty"
            ],
            "type": "string",
            "description": "What kind of property to search for. Filter mode only.",
            "default": "Apartment"
          },
          "roomsMin": {
            "title": "Min rooms / pièces (Filter mode)",
            "minimum": 1,
            "maximum": 10,
            "type": "integer",
            "description": "Minimum number of rooms (pièces), e.g. 3 returns 3, 4, 5… rooms. 6 means \"6 or more\". Applied as pap.fr's own rooms filter. Filter mode only."
          },
          "roomsMax": {
            "title": "Max rooms / pièces (Filter mode)",
            "minimum": 1,
            "maximum": 10,
            "type": "integer",
            "description": "Maximum number of rooms (pièces). Combine with Min rooms for a range, e.g. 2–3. 6 or more means no upper limit. Filter mode only."
          },
          "bedroomsMin": {
            "title": "Min bedrooms / chambres (Filter mode)",
            "minimum": 1,
            "maximum": 20,
            "type": "integer",
            "description": "Minimum number of bedrooms (chambres), applied by pap.fr's own search. Combine with Max bedrooms for a range. Filter mode only."
          },
          "bedroomsMax": {
            "title": "Max bedrooms / chambres (Filter mode)",
            "minimum": 1,
            "maximum": 20,
            "type": "integer",
            "description": "Maximum number of bedrooms (chambres). pap.fr's own search has no working maximum, so this is checked on each result: the listing's printed bedroom count must be at or below this value (a 1-room studio counts as 0 bedrooms; a listing that prints neither count is left out). Filter mode only."
          },
          "priceMin": {
            "title": "Min price € (Filter mode)",
            "minimum": 1,
            "type": "integer",
            "description": "Minimum price in euros (sale price, or monthly rent for rentals). Applied as pap.fr's own price filter. Filter mode only."
          },
          "priceMax": {
            "title": "Max price € (Filter mode)",
            "minimum": 1,
            "type": "integer",
            "description": "Maximum price in euros (sale price, or monthly rent for rentals). Filter mode only."
          },
          "surfaceMin": {
            "title": "Min living area m² (Filter mode)",
            "minimum": 1,
            "type": "integer",
            "description": "Minimum living area in m². Filter mode only."
          },
          "surfaceMax": {
            "title": "Max living area m² (Filter mode)",
            "minimum": 1,
            "type": "integer",
            "description": "Maximum living area in m². Filter mode only."
          },
          "landSurfaceMin": {
            "title": "Min land area m² (Filter mode)",
            "minimum": 1,
            "type": "integer",
            "description": "Minimum land/garden area in m² (houses and plots). Filter mode only."
          },
          "landSurfaceMax": {
            "title": "Max land area m² (Filter mode)",
            "minimum": 1,
            "type": "integer",
            "description": "Maximum land/garden area in m² (houses and plots). Filter mode only."
          },
          "propertyTypes": {
            "title": "Property types — several at once (Filter mode)",
            "type": "array",
            "description": "Optional. Pick one or more of pap.fr's own property categories, including ones the single Property type list doesn't have (whole buildings, life-annuity sales, houseboats, offices…). When set, this replaces Property type. Values pap.fr doesn't offer for the chosen Buy/Rent are ignored with a warning. Filter mode only.",
            "items": {
              "type": "string",
              "enum": [
                "maison",
                "appartement",
                "terrain",
                "garage-parking",
                "immeuble",
                "surface-a-amenager",
                "peniche",
                "mobil-home",
                "viager",
                "multipropriete",
                "residence-avec-service",
                "bureaux",
                "local-commercial",
                "fonds-de-commerce",
                "local-d-activite",
                "location-accession",
                "logement-contre-services",
                "divers"
              ],
              "enumTitles": [
                "Maison / House",
                "Appartement / Apartment",
                "Terrain / Plot (sale only)",
                "Garage, parking",
                "Immeuble / Whole building (sale only)",
                "Surface à aménager / Space to convert (sale only)",
                "Péniche / Houseboat",
                "Mobil-home, chalet",
                "Viager / Life annuity sale (sale only)",
                "Multipropriété / Timeshare (sale only)",
                "Résidence avec services / Serviced residence",
                "Bureaux / Offices",
                "Local commercial / Retail premises",
                "Fonds de commerce / Business for sale (sale only)",
                "Local d'activité / Light-industrial premises",
                "Location-accession / Rent-to-own (rent only)",
                "Logement contre services / Housing for services (rent only)",
                "Divers / Other"
              ]
            }
          },
          "features": {
            "title": "Features (Filter mode)",
            "type": "array",
            "description": "Optional. Only return listings pap.fr tags with ALL of these features. Some apply to sales only or rentals only; ones that don't fit the chosen Buy/Rent are ignored with a warning. Filter mode only.",
            "items": {
              "type": "string",
              "enum": [
                "ascenseur",
                "balcon-terrasse",
                "dernier-etage",
                "duplex-triplex",
                "garages-parkings",
                "piscine",
                "acces-handicape",
                "visite-virtuelle",
                "investissement-locatif",
                "meuble",
                "vide",
                "bail-mobilite",
                "coloc"
              ],
              "enumTitles": [
                "Ascenseur / Lift",
                "Balcon ou terrasse / Balcony or terrace",
                "Dernier étage / Top floor",
                "Duplex, triplex",
                "Garage ou parking / Garage or parking",
                "Piscine / Pool (sale only)",
                "Accès PMR / Step-free access",
                "Visite virtuelle / Virtual tour (sale only)",
                "Investissement locatif / Buy-to-let (sale only)",
                "Meublé / Furnished (rent only)",
                "Vide / Unfurnished (rent only)",
                "Bail mobilité / Short mobility lease (rent only)",
                "Colocation / Flat-share (rent only)"
              ]
            }
          },
          "excludeNewBuild": {
            "title": "Exclude new-build programmes (Filter mode, sales)",
            "type": "boolean",
            "description": "Hide new-build developer programmes from sale results. Sales only. Filter mode only.",
            "default": false
          },
          "strictLocation": {
            "title": "Exact location only (Filter mode)",
            "type": "boolean",
            "description": "When a place has few listings, pap.fr also shows listings from nearby places, marked “à N km de …”. Turn this on to keep only listings inside the place you searched. Off (default): nearby listings are included and each one carries its distance in distanceFromSearchKm. Filter mode only.",
            "default": false
          },
          "sortBy": {
            "title": "Sort order (Filter mode)",
            "enum": [
              "Default",
              "PriceAsc",
              "PriceDesc",
              "SurfaceAsc",
              "SurfaceDesc",
              "DateAsc"
            ],
            "type": "string",
            "description": "How to order results. Filter mode only — in URL mode the sort is taken from your pasted URL. Default = most recent first (PAP's own default).",
            "default": "Default"
          },
          "urls": {
            "title": "Search URLs (URL mode)",
            "type": "array",
            "description": "One or more pap.fr URLs: search pages, city pages or listing/detail pages (e.g. https://www.pap.fr/annonces/appartement-paris-18e-75018-r464203311). Tip: open pap.fr in your browser, pick property type + location + any price/surface/bedroom filters, then paste the resulting URL here. Every search path shape pap.fr emits passes through unchanged, including the alternative spellings pap.fr uses on its own page links (\"appartement-a-louer-…\", \"ventes-appart-…\"); see the README's URL shapes table. A city page (https://www.pap.fr/immobilier/<place>-g<id>) is converted to the full search for that place, sale or rent per Listing type. A pasted detail URL is fetched as a single listing. If a search URL ends with `-N` (page number), scraping starts at page N and walks forward. Any other URL (e.g. the bare pap.fr homepage) is skipped with a warning, not silently scraped as empty.",
            "items": {
              "type": "string"
            },
            "default": [
              "https://www.pap.fr/annonce/vente-appartements-paris-75-g439",
              "https://www.pap.fr/annonce/locations-appartement-paris-75-g439",
              "https://www.pap.fr/annonce/vente-appartements-paris-75-g439-3-pieces-tri-prix-asc-2",
              "https://www.pap.fr/annonce/appartement-a-louer-paris-75-g439-2",
              "https://www.pap.fr/annonce/vente-maisons-appartements-paris-75-g439",
              "https://www.pap.fr/annonce/vente-immobilier-paris-75-g439",
              "https://www.pap.fr/annonce/vente-appartements-paris-7e-g37774-studio-a-partir-de-1-chambres-jusqu-a-150000-euros",
              "https://www.pap.fr/annonce/vente-appartements-75",
              "https://www.pap.fr/annonce/vente-appartements-ile-de-france",
              "https://www.pap.fr/immobilier/paris-75-g439",
              "https://www.pap.fr/annonces/appartement-paris-18e-75018-r464203311"
            ]
          },
          "references": {
            "title": "Listing references (both modes)",
            "type": "array",
            "description": "Optional. pap.fr listing reference codes as printed on the listing (\"Réf. : G35/3579\"). Each one is looked up on pap.fr and returned as a single listing, in either mode. Leave Locations empty in Filter mode to look up references only.",
            "items": {
              "type": "string"
            }
          },
          "maxPages": {
            "title": "Max pages per search",
            "minimum": 0,
            "type": "integer",
            "description": "How many result pages to walk per location / URL. PAP returns 12 listings per page (+3 featured). Leave empty to walk every result page."
          },
          "maxListings": {
            "title": "Max total listings",
            "minimum": 0,
            "type": "integer",
            "description": "Hard cap across the whole run. 0 = unlimited (bounded only by Max pages).",
            "default": 20
          },
          "fetchDetails": {
            "title": "Visit each listing's detail page",
            "type": "boolean",
            "description": "Adds lat/lng, DPE/GES energy classes, street address, full seller description, reference number, bedrooms, floor, HOA charges, property tax, heating type, and the full high-res photo gallery. Turn off for a faster run with just the SERP-level fields (price, rooms, m², city, primary photo). Each listing whose detail page loads also bills the detail-enrichment charge event (see the Pricing tab); listings whose detail page could not be read are not billed for it.",
            "default": true
          },
          "proxy": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Residential proxy recommended. Some exits are refused and the scraper retries on fresh exits automatically. The default pins an Italian exit, which worked most reliably in our tests; if runs keep failing, clear the country or try another."
          },
          "resumeFromRunId": {
            "title": "Resume from a previous run (optional)",
            "type": "string",
            "description": "Paste a previous run ID or dataset ID to continue a full-catalogue walk across separate runs. Listings already collected there (matched by listing id) are skipped, so this run only saves the new ones. Leave empty for a normal fresh run. For recurring monitoring of the same search instead, use Incremental mode below."
          },
          "incrementalMode": {
            "title": "Incremental changes for scheduled runs",
            "type": "boolean",
            "description": "Turn this on for daily/weekly recurring monitoring of the same search. The first run returns all matching listings as NEW. Later runs return only NEW, UPDATED, and REAPPEARED listings by default. Turn on \"Emit unchanged listings\" or \"Emit expired listings\" only when you also want those rows returned (and billed). State is kept separately per search (location/URL, listing/property type, rooms, sort, and detail-fetch setting) — use State key below to name or deliberately share a monitoring campaign. 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 search inputs above (mode, locations/URLs, listing/property type, rooms, sort, detail-fetch setting) — 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, a block stopped it early, or Resume was used. This returns — and bills — extra synthetic rows, so leave it off unless you need expiry tracking. Reappeared listings (a previous EXPIRED id seen again) can only ever occur once this has been turned on for at least one earlier run.",
            "default": false
          },
          "ignoreFieldsForChanges": {
            "title": "Ignore fields when detecting changes (incremental mode only)",
            "type": "array",
            "description": "Optional. Field names to exclude from change detection on top of the built-in defaults (currently just the per-fetch `scrapedAt` timestamp) — use this if you notice a field flipping every run for a reason you don't care about. A bare name ignores a top-level field (e.g. `priceDisplay`); a dotted path ignores one nested field (`seller.phone`); a path ending in `.*` ignores an entire nested object (`seller.*`, `additionalProperties.*`). Ignored fields are still returned in every row — only `changeType`/`changedFields` detection ignores them. Leave empty to use only the built-in defaults.",
            "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 → Integrations, 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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}