{
  "openapi": "3.0.1",
  "info": {
    "title": "Wallapop Cars Scraper — Used Cars & Vans in Spain",
    "description": "Scrape used car and van listings from Wallapop Spain: price, mileage, year, fuel, gearbox, city and photos. Filter by brand, model, price, year or city. Incremental mode returns only new or changed listings. No login or API key. $1 per 1,000 listings.",
    "version": "0.6",
    "x-build-id": "xaezAVzTl29CEhnAh"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/rastriq~wallapop-cars-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-rastriq-wallapop-cars-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/rastriq~wallapop-cars-scraper/runs": {
      "post": {
        "operationId": "runs-sync-rastriq-wallapop-cars-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/rastriq~wallapop-cars-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-rastriq-wallapop-cars-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": {
          "keywords": {
            "title": "🔍 Search keywords",
            "type": "string",
            "description": "<b>Free-text search across make, model and trim.</b><br>Examples: <code>BMW Serie 3</code>, <code>Subaru Outback</code>, <code>Seat Leon FR</code>.<br>Vans work too: <code>furgoneta</code>, <code>Renault Trafic</code>. Leave empty to browse the full car category."
          },
          "vehicleCategory": {
            "title": "🚗 Vehicle category",
            "enum": [
              "cars",
              "motorbikes"
            ],
            "type": "string",
            "description": "<b>What to search.</b> <code>Cars</code> (default) also covers vans — use keywords such as <code>furgoneta</code>. <code>Motorbikes</code> searches Wallapop's motorbike category (brand/model/year/km are filled when Wallapop provides them).",
            "default": "cars"
          },
          "maxItems": {
            "title": "📊 Max results",
            "minimum": 1,
            "maximum": 100000,
            "type": "integer",
            "description": "<b>Hard cap on the number of listings returned.</b><br>The default of <b>50</b> finishes in under a minute. Raise it for full exports — 500 items ≈ 1 min, 5 000 items ≈ 5–8 min.<br>For nationwide ingestion with <code>orderBy: newest</code>, set 50 000+ to capture all daily activity.",
            "default": 50
          },
          "location": {
            "title": "📍 Search center",
            "enum": [
              "espana",
              "madrid",
              "barcelona",
              "valencia",
              "sevilla",
              "bilbao",
              "malaga",
              "zaragoza"
            ],
            "type": "string",
            "description": "City used as the geographic center of the search. Ignored when <code>Custom latitude</code> and <code>Custom longitude</code> are both set.",
            "default": "madrid"
          },
          "minPrice": {
            "title": "💶 Min price (€)",
            "minimum": 0,
            "type": "integer",
            "description": "Only return listings priced at or above this amount."
          },
          "maxPrice": {
            "title": "💶 Max price (€)",
            "minimum": 0,
            "type": "integer",
            "description": "Only return listings priced at or below this amount."
          },
          "minYear": {
            "title": "📅 Min year",
            "minimum": 1950,
            "maximum": 2030,
            "type": "integer",
            "description": "Oldest registration year to include."
          },
          "maxYear": {
            "title": "📅 Max year",
            "minimum": 1950,
            "maximum": 2030,
            "type": "integer",
            "description": "Newest registration year to include."
          },
          "engine": {
            "title": "⛽ Fuel type",
            "enum": [
              "gasoline",
              "gasoil",
              "electric-hybrid",
              "hybride",
              "hybride_plugin",
              "lpg"
            ],
            "type": "string",
            "description": "Filter by engine fuel type."
          },
          "gearbox": {
            "title": "⚙️ Gearbox",
            "enum": [
              "manual",
              "automatic",
              "semiautomatic"
            ],
            "type": "string",
            "description": "Filter by transmission type."
          },
          "sellerType": {
            "title": "👤 Seller type",
            "enum": [
              "private",
              "professional"
            ],
            "type": "string",
            "description": "<b>Filter by seller profile.</b><br>When used with <code>enableCursor</code>, each seller type gets its own independent cursor — so you can run parallel private and professional streams without interference.<br><br><i>Note: the output field <code>seller_type</code> stays empty in listing rows (Wallapop's search does not return it). This filter works server-side; use <b>Seller profiles</b> to identify dealers.</i>"
          },
          "orderBy": {
            "title": "📶 Sort order",
            "enum": [
              "most_relevance",
              "newest",
              "price_low_to_high",
              "price_high_to_low",
              "closest"
            ],
            "type": "string",
            "description": "<b>How results are ordered.</b><br><code>Newest first</code> returns listings from all of Spain sorted by date — ideal for continuous nationwide ingestion.<br><code>Closest</code> fans out from the search center by proximity — ideal for geographic snapshots.",
            "default": "most_relevance"
          },
          "distanceKm": {
            "title": "📏 Search radius (km)",
            "minimum": 1,
            "maximum": 1000,
            "type": "integer",
            "description": "<b>Maximum distance in km from the search center.</b><br>Only applies when <code>orderBy</code> is set to <code>Closest</code>.<br>Leave empty for no radius limit.<br>Example: <code>50</code> → only listings within 50 km of the search center."
          },
          "geoStopPostalPrefix": {
            "title": "🗺️ Geographic stop — postal prefix",
            "type": "string",
            "description": "<b>Optional.</b> Stop the sweep once it leaves this postal area. Example: <code>48</code> for Bizkaia.<br><br>Wallapop honours <code>distanceKm</code> as a hard cut, but a circle is not a province: a 65&nbsp;km disc around Bilbao also contains Álava, half of Gipuzkoa and part of Cantabria. With <code>orderBy=closest</code> the sweep works outward, so once several consecutive pages sit outside the prefix there is nothing left to find inside it.<br><br>Leave empty to disable. Listings with no postal code are never counted as outside."
          },
          "geoStopThreshold": {
            "title": "📐 Drift threshold",
            "minimum": 0.1,
            "maximum": 1,
            "type": "number",
            "description": "Fraction of a page outside the prefix for that page to count as drift.",
            "default": 0.5
          },
          "geoStopPages": {
            "title": "📄 Consecutive drift pages",
            "minimum": 1,
            "maximum": 20,
            "type": "integer",
            "description": "Consecutive drift pages before stopping. The streak resets if a page comes back inside, so a single border page cannot end the sweep.",
            "default": 3
          },
          "timeFilter": {
            "title": "🕐 Time filter",
            "enum": [
              "today",
              "lastWeek"
            ],
            "type": "string",
            "description": "<b>Restrict results by when a listing was last MODIFIED — not when it was published.</b><br><br>Measured against the live API: with <code>today</code>, only 8 of 318 results had gone more than 24 h without a modification, versus 317 of 320 unfiltered. So the filter works — but it works on <code>modified_at</code>.<br><br><b>What that means in practice:</b><br>• A listing published two years ago and edited this morning <b>is</b> returned by <code>today</code>. We measured one 786 days old.<br>• A listing published yesterday and untouched since <b>is not</b>.<br><br><b>Do not use this to capture new supply.</b> These feeds bump and re-index constantly, so recency of modification says little about recency of publication. Use incremental mode (<code>enableCursor</code>) for that — the ledger is what distinguishes a genuinely new listing from one that merely moved.<br><br>Where it does help: sweeping for <i>recent activity</i> — price changes and bumps — without scanning the rest of the catalogue.<br><br>Note that <code>today</code>, <code>lastWeek</code> and <code>lastMonth</code> returned identical result sets in testing (238 of 238), because the feed is dominated by recently bumped listings. Treat the granularity between values as unreliable."
          },
          "customLatitude": {
            "title": "🌐 Custom latitude",
            "minimum": 27,
            "maximum": 44,
            "type": "number",
            "description": "<b>Latitude of your custom search center.</b><br>Range: <code>27.0</code> (Canarias) to <code>44.0</code> (Pyrenees).<br>Example: <code>42.84998</code> → Vitoria-Gasteiz<br>Example: <code>28.12357</code> → Las Palmas de Gran Canaria"
          },
          "customLongitude": {
            "title": "🌐 Custom longitude",
            "minimum": -18.2,
            "maximum": 5,
            "type": "number",
            "description": "<b>Longitude to pair with custom latitude.</b><br>Range: <code>-18.2</code> (western Canarias) to <code>5.0</code> (Balearics).<br>Example: <code>-2.67268</code> → Vitoria-Gasteiz<br>Example: <code>-15.43620</code> → Las Palmas de Gran Canaria"
          },
          "maxPages": {
            "title": "📑 Max pages",
            "minimum": 0,
            "maximum": 2000,
            "type": "integer",
            "description": "<b>Hard cap on search-result pages swept.</b> ~35 listings per page.<br>Leave at 0 for automatic: enough pages to satisfy <b>Max results</b> in normal mode, or 30 pages (~1 000 listings scanned) in incremental mode, where most listings are skipped as unchanged and more pages must be walked to find the new ones.",
            "default": 0
          },
          "enableCursor": {
            "title": "🔄 Incremental mode (delta engine)",
            "type": "boolean",
            "description": "<b>Return only listings that are new or have changed since your last run.</b><br>The actor keeps a ledger of every listing id it has already delivered for this search stream, together with a fingerprint of <code>price / km / title / reserved</code>. A listing is returned when its id is unknown (<code>_delta_status: \"new\"</code>) or when its fingerprint moved (<code>_delta_status: \"updated\"</code>). Everything else is skipped and not charged.<br><br>The ledger makes no assumption about feed ordering or timestamps, so a listing that surfaces late in Wallapop's rotating feed is still captured.<br><br><b>First run:</b> captures a full baseline and seeds the ledger.<br><b>Subsequent runs:</b> new and changed listings only.<br><br>Use <code>cursorId</code> to keep parallel searches independent.",
            "default": false
          },
          "cursorId": {
            "title": "🏷️ Stream id (cursor namespace)",
            "type": "string",
            "description": "<b>Optional.</b> Names the ingestion stream this run belongs to. Runs sharing a stream id share one ledger; different ids are fully independent.<br><br>Leave empty and the actor derives a stable id from your search filters, which is normally what you want. Set it explicitly when several searches should feed a single catalogue (e.g. <code>catalogue-es</code>), or to force a clean rebuild by using a new value.<br><br>Only used when <b>Incremental mode</b> is on."
          },
          "emitSeenIds": {
            "title": "📤 Emit seen ids (delisting detection)",
            "type": "boolean",
            "description": "<b>Write every listing id observed during the sweep to the run's key-value store</b> under <code>SEEN_IDS</code> — including the ones skipped as unchanged.<br><br>With delta ingestion your catalogue never expires rows on its own: a vehicle that sells simply stops appearing. Compare <code>SEEN_IDS</code> across runs and mark anything absent for N consecutive sweeps as sold.<br><br>No extra cost.",
            "default": false
          },
          "stripSellerPII": {
            "title": "🔒 Strip seller personal data (GDPR)",
            "type": "boolean",
            "description": "<b>Remove personal data of private sellers from the output.</b><br>When enabled: <code>user_id</code> is set to null, coordinates are truncated to ~1 km precision, and phone numbers / emails embedded in descriptions are redacted.<br><br>Professional seller data is not affected — their details are commercial, not personal.<br><br>Enable this for GDPR-compliant pipelines where individual seller identification is not needed.",
            "default": false
          },
          "sellerProfiles": {
            "title": "👤 Seller profiles (user IDs)",
            "type": "array",
            "description": "<b>Leave empty to search car listings (normal mode).</b><br><br>Enter one or more Wallapop seller <code>user_id</code> values (the <code>user_id</code> field of the listing output, e.g. <code>abc123xyz789</code>), one per line. When this list has at least one ID, the actor <b>does not search listings</b>: it fetches the public profile of each account and outputs one record per account with <code>record_type: \"seller_profile\"</code> — name, seller type, city, postal code, coordinates, address, website, active listings count, profile URL and registration date.<br><br>🔒 Profiles of <b>private</b> (non-professional) accounts are reduced to <code>user_id</code> + <code>is_professional: false</code> — no name or location. Unknown IDs return a record with <code>error</code> and do not stop the run.",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}