# PAP.fr Scraper — French FSBO Real Estate Listings (No Agencies) (`studio-amba/pap-fr-scraper`) Actor

Scrape 100% owner-direct real estate listings from pap.fr (Particulier à Particulier), France's largest no-agency property portal. Every listing is FSBO by design — no agencies allowed. Extract price, surface, rooms, city, postal code, and photos for sale and rental listings.

- **URL**: https://apify.com/studio-amba/pap-fr-scraper.md
- **Developed by:** [Studio Amba](https://apify.com/studio-amba) (community)
- **Categories:** Real estate
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.00 / 1,000 result scrapeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## PAP.fr Scraper

Extract 100% owner-direct real estate listings from [pap.fr](https://www.pap.fr) (Particulier à Particulier) — France's largest no-agency property portal — with prices, surface, rooms, location, and photos for sale and rental listings.

### What is PAP.fr Scraper?

**PAP.fr Scraper** taps into pap.fr, a French property portal that by design only accepts listings from private sellers. No real estate agency can list on pap.fr — it is structurally FSBO (For Sale By Owner). That makes it fundamentally different from portals like SeLoger, LeBonCoin, or Bien'ici, where agency and private listings sit side by side and you have to infer which is which from an "agency name present/absent" heuristic that's often wrong.

- **Find owner-direct leads without guesswork:** every row this actor returns carries an explicit `sellerType: "particulier"` marker and `agencyName: null` — not inferred, not a candidate signal, a structural fact about the source
- **Feed FSBO lead-generation tools:** agencies and canvassing services pay for lists of properties sold without an agency mandate. pap.fr is the cleanest single source for that signal in France
- **Track the private-seller segment of the market:** compare owner-direct asking prices against agency-listed prices for the same city and property type
- **Build cross-portal deduplication pipelines:** combine with agency-heavy portals (Bien'ici, SeLoger) to see which properties are exclusively owner-direct versus dual-listed
- **Monitor new owner listings:** schedule runs to catch new private-seller inventory the moment it's posted, before agencies pick it up

The scraper reads pap.fr's server-rendered search result pages directly — no per-listing detail fetch needed — which keeps it fast and cheap.

### What data does PAP.fr Scraper extract?

🏠 **Title** — property title (usually district + postal code)
💰 **Price** — asking price or monthly rent in EUR
🏗️ **Property type** — apartment, house, studio, land, parking, or other
🔑 **Listing type** — sale or rent
✅ **Seller type** — always `"particulier"` (private individual) — the explicit FSBO marker, true by construction on pap.fr
🚫 **Agency name** — always `null` — pap.fr never carries agency inventory
👤 **Seller name** — included for shape-compatibility with other portals; pap.fr does not expose an individual seller name anywhere (always `null` today)
📍 **City** and **postal code**
📐 **Surface** in square meters
🛏️ **Rooms** and **bedrooms**
📝 **Description** snippet
📸 **Primary image** and full **photo carousel** URLs
🔗 **Direct URL** to the listing on pap.fr

### How to scrape pap.fr data

Configure the scraper through the Apify Console or via the API. Only `location` is required — everything else has a sensible default.

#### Input options

| Input | Type | Default | Description |
|-------|------|---------|-------------|
| **City** | string | `Paris` | French city to search (e.g., `Paris`, `Lyon`, `Marseille`, `Bordeaux`). Matched against a curated list of major French cities; unrecognized cities fall back to Paris |
| **Transaction Type** | `sale` / `rent` | `sale` | Buy (vente) or rent (location) |
| **Property Type** | select | All types | Apartment, house, studio, land, or parking/garage |
| **Min Price** | integer | — | Minimum price in EUR, applied after fetching |
| **Max Price** | integer | — | Maximum price in EUR, applied after fetching |
| **Max Results** | integer | `100` | Maximum listings to return |
| **Bright Data API Key** | string (secret) | — | Optional — provide your own key, or leave empty to use the built-in unlocking service |
| **Proxy Configuration** | object | — | Legacy field, ignored — see "How the scraper reaches pap.fr" below |

#### How the scraper reaches pap.fr

pap.fr sits behind Cloudflare with an interactive Turnstile challenge ("Verify you are human"). Plain HTTP requests and standard headless-browser requests both get stopped at the challenge page before any listing data loads. This actor routes every request through Bright Data's Web Unlocker, which clears the challenge and returns the real page HTML. Apify's own Proxy product cannot pass this challenge, which is why the legacy `proxyConfiguration` field is accepted but ignored.

pap.fr's `robots.txt` disallows query-string search URLs (`/*?*`) and several path prefixes site-wide. This actor only ever requests path-based, robots-allowed URLs — search-result pages scoped by pap.fr's internal numeric location ID, and listing detail links under `/annonces/...-r{id}`. Price filters are applied after fetching rather than as URL parameters, since pap.fr doesn't expose a robots-compliant path for them.

#### Tips for best results

- **Stick to the supported city list** for reliable location scoping — pap.fr's search requires an internal geo ID per city, and there's no public geocoding endpoint to resolve arbitrary city names (`/geo/` is robots-disallowed). Supported cities today: Paris, Lyon, Marseille, Bordeaux, Nantes, Toulouse, Nice, Lille, Aix-en-Provence, Cannes, Dijon, Montpellier, Grenoble, Boulogne-Billancourt, Saint-Denis, and the Île-de-France region
- **Leave Property Type empty** to get every listing type for a city in one run — the actor detects each listing's actual property type from its URL slug
- **Combine sale + rent runs** if you need both — they're two separate searches on pap.fr, so run the actor twice with different `transactionType` values

### Output

Results are stored in a dataset you can download as JSON, CSV, Excel, XML, or HTML from the Apify Console.

#### JSON example

```json
{
    "title": "Lyon 2E (69002)",
    "price": 495000,
    "currency": "EUR",
    "listingType": "sale",
    "propertyType": "apartment",
    "sellerType": "particulier",
    "agencyName": null,
    "sellerName": null,
    "city": "Lyon 2E",
    "postalCode": "69002",
    "surface": 76.56,
    "rooms": 2,
    "bedrooms": 1,
    "description": "À proximité immédiate de la place Bellecour, agréable duplex entièrement rénové en 2023, offrant 76,56 m² de surface au sol (57,35 m² loi carrez)...",
    "imageUrl": "https://cdn.pap.fr/photos/pap/85/a0/85a023348c10cd387641a8b1535b2bb8/8-p2.webp",
    "imageUrls": [
        "https://cdn.pap.fr/photos/pap/85/a0/85a023348c10cd387641a8b1535b2bb8/8-p2.webp",
        "https://cdn.pap.fr/photos/pap/b2/8c/b28c4783336bb3532102099ee405964b/b-p2.webp"
    ],
    "url": "https://www.pap.fr/annonces/appartement-lyon-2e-69002-r463903677",
    "scrapedAt": "2026-07-14T20:59:52.614Z"
}
````

#### Why `sellerType` is the whole point

Most French real-estate portals mix agency and private listings, so any FSBO scraper built on them has to infer seller type from clues — whether an agency name field is empty, whether a "professional" flag is set, whether the phone number matches a known agency. Those signals are noisy and portals frequently omit or obscure them.

pap.fr removes the guesswork: the platform's own terms only allow private sellers, and its structured data confirms it on every single listing (`"seller":{"@type":"Person","name":"Particulier"}` in pap.fr's own JSON-LD, and "Contacter le propriétaire" — never an agency name — in the contact box). This actor surfaces that as a literal, unconditional field: `sellerType: "particulier"` and `agencyName: null` on every row, every time. Downstream lead pipelines can trust it without a confidence score.

### How much does it cost to scrape pap.fr?

PAP.fr Scraper reads search-result list pages only — it does not fetch a separate detail page per listing, so the request-to-result ratio stays low (roughly one Bright Data request per ~12 listings).

| Scenario | Est. cost | Time |
|----------|-----------|------|
| 25 listings | ~$0.005 | ~20 sec |
| 100 listings | ~$0.02 | ~1 min |
| 500 listings | ~$0.10 | ~4 min |

### Can I integrate PAP.fr Scraper with other apps?

Yes. PAP.fr Scraper connects with any tool through [Apify integrations](https://apify.com/integrations):

- **Google Sheets** — export owner-direct listings to a live spreadsheet, updated on every run
- **Slack / Email** — get instant alerts when new private-seller listings appear in your target city
- **Zapier / Make** — build automation workflows triggered by new FSBO leads
- **Airtable** — build a filterable owner-direct property database
- **REST API** — call the scraper on demand from any programming language
- **Webhooks** — receive a callback when scraping finishes to trigger downstream processing

### Can I use PAP.fr Scraper as an API?

Yes. Use the [Apify API](https://docs.apify.com/api/v2) to run PAP.fr Scraper programmatically.

**Python:**

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")
run = client.actor("studio-amba/pap-fr-scraper").call(run_input={
    "location": "Paris",
    "transactionType": "sale",
    "propertyType": "apartment",
    "maxResults": 100,
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(f"{item['title']} — €{item['price']:,} — {item.get('surface', '?')} m² — {item['sellerType']}")
```

**JavaScript:**

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: 'YOUR_API_TOKEN' });
const run = await client.actor('studio-amba/pap-fr-scraper').call({
    location: 'Lyon',
    transactionType: 'rent',
    maxResults: 50,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach(item => console.log(`${item.title} — €${item.price?.toLocaleString() ?? '?'} — FSBO: ${item.sellerType}`));
```

Check the [API tab](https://apify.com/studio-amba/pap-fr-scraper/api) for full documentation.

### FAQ

#### What is pap.fr?

pap.fr (Particulier à Particulier, "individual to individual") is one of France's oldest and largest real estate portals, operating since 1975. Unlike SeLoger, LeBonCoin, or Bien'ici, it has always been agency-free by policy — it only accepts listings posted directly by property owners.

#### How does PAP.fr Scraper work?

The scraper requests pap.fr's server-rendered search-result pages (scoped by city and property type) through Bright Data's Web Unlocker, which clears pap.fr's Cloudflare Turnstile challenge. It parses each listing card directly from the HTML — no separate detail-page fetch per listing — extracting price, title, location, room counts, description, and the full photo set that pap.fr already embeds in the list view.

#### Are there really zero agency listings mixed in?

pap.fr occasionally shows sponsored ads for new-build developments (via a partner site, immoneuf.com) alongside real listings on search pages. The scraper explicitly filters these out — they link off pap.fr's own domain and are excluded before any row is written to the dataset, so every row that reaches you is a genuine pap.fr private-seller listing.

#### Why isn't there a real seller name in the data?

pap.fr's contact flow says "Contacter le propriétaire" (contact the owner) and shows a phone number, but does not surface the owner's name anywhere on the public page — list or detail. The `sellerName` field exists in the output for shape-compatibility with other portals that do expose this, but on pap.fr it's always `null` today.

#### Is it legal to scrape pap.fr?

This scraper extracts publicly available property listing data that pap.fr displays to all visitors — factual real estate information (prices, locations, property characteristics) published by the sellers themselves. Use the data responsibly and in compliance with French and EU regulations.

#### How fresh is the data?

Every run fetches pap.fr's live search results at request time. Schedule daily or weekly runs to maintain an up-to-date dataset of current listings.

### Limitations

- **Curated city list.** Location scoping requires pap.fr's internal geo ID, and there's no public geocoding endpoint to resolve arbitrary city names. Cities outside the supported list fall back to Paris.
- **No historical pricing.** The scraper captures the current asking price at the time of scraping. To track price changes, schedule recurring runs and compare datasets.
- **List-page data only.** Description is the shortened list-view snippet, not the full listing description — the actor intentionally skips per-listing detail-page fetches to stay fast and cheap.
- **No phone numbers.** pap.fr shows the owner's phone number on the detail page, but this actor does not collect it to stay conservative on personal data.
- **Photo URLs** point to pap.fr's CDN and may expire after the listing is removed. Download images promptly if you need them long-term.

### Other real estate scrapers

Build a France-wide property dataset by combining PAP.fr Scraper with these actors:

- 🇫🇷 [Logic-Immo Scraper](https://apify.com/studio-amba/logicimmo-scraper) — French real estate listings (agency + private)
- 🇱🇺 [atHome.lu Scraper](https://apify.com/studio-amba/athome-scraper) — Luxembourg real estate listings
- 🏛️ [Biddit Scraper](https://apify.com/studio-amba/biddit-scraper) — Belgian notarial property auctions
- 🏡 [Immovlan Scraper](https://apify.com/studio-amba/immovlan-scraper) — Belgian property listings

### Your feedback

Have a question, found a bug, or want a new feature? Open an issue on the [Issues tab](https://apify.com/studio-amba/pap-fr-scraper/issues). We actively maintain this scraper and respond to all reports.

### Need this data on a schedule, or a custom version?

We run this scraper as a managed service for businesses: scheduled runs,
deduplication, delta detection, and delivery to your inbox, Google Sheets,
or API — maintenance included. We can also build a custom version with your
exact fields and filters, or combine multiple sources into one feed.

See [studioamba.dev/services](https://studioamba.dev/services/) or email
<hello@studioamba.dev> for a free data sample.
We maintain 300+ European web scrapers and answer within one business day.

# Actor input Schema

## `location` (type: `string`):

French city to search (e.g., 'Paris', 'Lyon', 'Marseille', 'Bordeaux'). Matched against a list of major French cities. Unrecognized cities fall back to Paris.

## `transactionType` (type: `string`):

Buy (vente) or rent (location).

## `propertyType` (type: `string`):

Filter by property type. Leave empty for all types.

## `minPrice` (type: `integer`):

Minimum price filter, applied after fetching (pap.fr search URLs don't support price query params under a robots-compliant path).

## `maxPrice` (type: `integer`):

Maximum price filter, applied after fetching.

## `maxResults` (type: `integer`):

Maximum number of listings to return.

## `brightDataApiKey` (type: `string`):

Optional: your own Bright Data API key for the Web Unlocker zone. Leave empty to use the built-in unlocking service. Required because pap.fr sits behind a Cloudflare Turnstile challenge that blocks plain HTTP and Apify Proxy requests.

## `proxyConfiguration` (type: `object`):

Legacy field, kept for backwards compatibility. Fetching goes through the built-in Bright Data Web Unlocker (needed to pass pap.fr's Cloudflare Turnstile challenge), so this is ignored.

## Actor input object example

```json
{
  "location": "Paris",
  "transactionType": "sale",
  "propertyType": "",
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "location": "Paris",
    "transactionType": "sale",
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("studio-amba/pap-fr-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "location": "Paris",
    "transactionType": "sale",
    "maxResults": 20,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("studio-amba/pap-fr-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "location": "Paris",
  "transactionType": "sale",
  "maxResults": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call studio-amba/pap-fr-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=studio-amba/pap-fr-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "PAP.fr Scraper — French FSBO Real Estate Listings (No Agencies)",
        "description": "Scrape 100% owner-direct real estate listings from pap.fr (Particulier à Particulier), France's largest no-agency property portal. Every listing is FSBO by design — no agencies allowed. Extract price, surface, rooms, city, postal code, and photos for sale and rental listings.",
        "version": "0.1",
        "x-build-id": "qFqoZiLvYuMx38fFx"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/studio-amba~pap-fr-scraper/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-studio-amba-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/studio-amba~pap-fr-scraper/runs": {
            "post": {
                "operationId": "runs-sync-studio-amba-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/studio-amba~pap-fr-scraper/run-sync": {
            "post": {
                "operationId": "run-sync-studio-amba-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": {
                    "location": {
                        "title": "City",
                        "type": "string",
                        "description": "French city to search (e.g., 'Paris', 'Lyon', 'Marseille', 'Bordeaux'). Matched against a list of major French cities. Unrecognized cities fall back to Paris.",
                        "default": "Paris"
                    },
                    "transactionType": {
                        "title": "Transaction Type",
                        "enum": [
                            "sale",
                            "rent"
                        ],
                        "type": "string",
                        "description": "Buy (vente) or rent (location).",
                        "default": "sale"
                    },
                    "propertyType": {
                        "title": "Property Type",
                        "enum": [
                            "",
                            "apartment",
                            "house",
                            "studio",
                            "land",
                            "parking"
                        ],
                        "type": "string",
                        "description": "Filter by property type. Leave empty for all types.",
                        "default": ""
                    },
                    "minPrice": {
                        "title": "Min Price (EUR)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Minimum price filter, applied after fetching (pap.fr search URLs don't support price query params under a robots-compliant path)."
                    },
                    "maxPrice": {
                        "title": "Max Price (EUR)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Maximum price filter, applied after fetching."
                    },
                    "maxResults": {
                        "title": "Max Results",
                        "minimum": 1,
                        "maximum": 2000,
                        "type": "integer",
                        "description": "Maximum number of listings to return.",
                        "default": 100
                    },
                    "brightDataApiKey": {
                        "title": "Bright Data API Key (optional)",
                        "type": "string",
                        "description": "Optional: your own Bright Data API key for the Web Unlocker zone. Leave empty to use the built-in unlocking service. Required because pap.fr sits behind a Cloudflare Turnstile challenge that blocks plain HTTP and Apify Proxy requests."
                    },
                    "proxyConfiguration": {
                        "title": "Proxy Configuration",
                        "type": "object",
                        "description": "Legacy field, kept for backwards compatibility. Fetching goes through the built-in Bright Data Web Unlocker (needed to pass pap.fr's Cloudflare Turnstile challenge), so this is ignored."
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
