{
  "openapi": "3.0.1",
  "info": {
    "title": "Tori.fi Scraper: Finland Classifieds and Prices",
    "description": "Tori.fi ads from Finland's largest second hand marketplace by keyword, category, region, postal code, radius or shop, 15,000 ads a search, no login. Rows: price in EUR, sale or give away, private or company, ToriDiili; ad pages add condition, Y-tunnus. Free price summary, JSON or CSV, pay per ad.",
    "version": "0.1",
    "x-build-id": "lwbTHXRdQop5Lohpn"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/automation_craft~tori-scraper/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-automation_craft-tori-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/automation_craft~tori-scraper/runs": {
      "post": {
        "operationId": "runs-sync-automation_craft-tori-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/automation_craft~tori-scraper/run-sync": {
      "post": {
        "operationId": "run-sync-automation_craft-tori-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": "Keywords",
            "type": "array",
            "description": "Search words, each one its own search (\"sohva\", \"iittala\", \"lastenrattaat\", \"talvirenkaat\", \"lego technic\"). Tori matches them in the ad texts. Left empty, each search reads without words, newest first.",
            "items": {
              "type": "string"
            }
          },
          "categories": {
            "title": "Categories",
            "type": "array",
            "description": "Tori categories, sub categories or product categories by Tori's Finnish name (\"Koti ja sisustus\", \"Sohvat ja lepotuolit\", \"Puhelimet ja tarvikkeet\") or Tori's value (\"0.78\"). Each category is its own search, with its own price summary.",
            "items": {
              "type": "string",
              "enumSuggestedValues": [
                "Antiikki ja taide",
                "Auto-, vene- ja moottoripyörätarvikkeet",
                "Elektroniikka ja kodinkoneet",
                "Eläimet ja eläintarvikkeet",
                "Koti ja sisustus",
                "Lapset ja vanhemmat",
                "Liiketoiminta ja palvelut",
                "Piha ja remontointi",
                "Urheilu ja ulkoilu",
                "Vaatteet, kosmetiikka ja asusteet",
                "Viihde ja harrastukset"
              ]
            }
          },
          "shopIds": {
            "title": "Shops (all ads of a shop)",
            "type": "array",
            "description": "Every ad of one Tori shop (a company seller): the shop's id (the companyId of a company row) or its shop page link (https://www.tori.fi/tori-kaupat/<shop>, the companyPageUrl of a company row; the shop's id is read from that page first, free). Each shop is its own search with Tori's own shop filter; keywords, categories and filters narrow it.",
            "items": {
              "type": "string"
            }
          },
          "locations": {
            "title": "Places",
            "type": "array",
            "description": "Tori's regions (\"Uusimaa\", \"Pirkanmaa\", \"Varsinais-Suomi\"), municipalities (\"Helsinki\", \"Tampere\", \"Oulu\") or districts (\"Malmi\", \"Hervanta\") by Tori's name, or Tori's value (\"0.100018\"), or a Finnish postal code (\"00700\", \"33720\"; Tori's district of that code). Several places are one search (any of them).",
            "items": {
              "type": "string",
              "enumSuggestedValues": [
                "Ahvenanmaa",
                "Etelä-Karjala",
                "Etelä-Pohjanmaa",
                "Etelä-Savo",
                "Kainuu",
                "Kanta-Häme",
                "Keski-Pohjanmaa",
                "Keski-Suomi",
                "Kymenlaakso",
                "Lappi",
                "Pirkanmaa",
                "Pohjanmaa",
                "Pohjois-Karjala",
                "Pohjois-Pohjanmaa",
                "Pohjois-Savo",
                "Päijät-Häme",
                "Satakunta",
                "Uusimaa",
                "Varsinais-Suomi"
              ]
            }
          },
          "latitude": {
            "title": "Latitude",
            "minimum": 59.4,
            "maximum": 70.2,
            "type": "number",
            "description": "With longitude and radiusKm: search around a point in Finland (Tori's own map radius)."
          },
          "longitude": {
            "title": "Longitude",
            "minimum": 19,
            "maximum": 31.7,
            "type": "number",
            "description": "With latitude and radiusKm."
          },
          "radiusKm": {
            "title": "Radius (km)",
            "minimum": 1,
            "maximum": 500,
            "type": "integer",
            "description": "With latitude and longitude: the distance in kilometres."
          },
          "minPrice": {
            "title": "Minimum price",
            "minimum": 0,
            "maximum": 1000000000,
            "type": "integer",
            "description": "The lowest price in euros, sent to Tori."
          },
          "maxPrice": {
            "title": "Maximum price",
            "minimum": 0,
            "maximum": 1000000000,
            "type": "integer",
            "description": "The highest price in euros, sent to Tori."
          },
          "sellerType": {
            "title": "Seller",
            "enum": [
              "any",
              "private",
              "business"
            ],
            "type": "string",
            "description": "Private sellers only, or companies only (Tori's own seller filter, \"Yksityinen\" or \"Yritys\").",
            "default": "any"
          },
          "postedToday": {
            "title": "Published today",
            "type": "boolean",
            "description": "Only ads Tori marks as published today (\"Julkaistu tänään\").",
            "default": false
          },
          "conditions": {
            "title": "Condition",
            "type": "array",
            "description": "Tori's condition labels: \"Uusi\" (new), \"Kuin uusi\" (like new), \"Hyvä\" (good), \"Kohtalainen\" (fair), \"Vaatii korjausta\" (needs repair).",
            "items": {
              "type": "string"
            }
          },
          "tradeTypes": {
            "title": "Ad type",
            "type": "array",
            "description": "\"Myydään\" (for sale), \"Annetaan\" (given away free) or \"Ostetaan\" (wanted).",
            "items": {
              "type": "string"
            }
          },
          "brands": {
            "title": "Brands",
            "type": "array",
            "description": "Brands as Tori lists them for the search (\"IKEA\", \"Iittala\", \"Marimekko\", \"Apple\", \"Stokke\" and about 1,700 more).",
            "items": {
              "type": "string"
            }
          },
          "shippingOnly": {
            "title": "ToriDiili only",
            "type": "boolean",
            "description": "Only ads sold with Tori's own shipping and payment service (\"ToriDiili\"). For free delivery only, use attributeFilters {\"shipping_types\": [\"Ilmainen toimitus\"]}.",
            "default": false
          },
          "attributeFilters": {
            "title": "Any other Tori filter",
            "type": "object",
            "description": "Any other filter of the search's own Tori filter list, by Tori's name or Finnish label, with values by label or value, or {\"min\": n, \"max\": n} for a range. For example {\"shipping_types\": [\"Ilmainen toimitus\"]} (free delivery). A filter the search does not offer is refused with the filters it does offer."
          },
          "postedAfter": {
            "title": "Posted on or after",
            "type": "string",
            "description": "Only ads published on or after this day in Finland (YYYY-MM-DD), checked on every row."
          },
          "postedWithinHours": {
            "title": "Posted within (hours)",
            "minimum": 1,
            "maximum": 8760,
            "type": "integer",
            "description": "Only ads published within this many hours of the run's start, checked on every row. Tori lists a search without words newest first, so for a short window turn on \"Published today\" too (Tori then sends only today's ads)."
          },
          "postedBefore": {
            "title": "Posted before",
            "type": "string",
            "description": "Only ads published before this day in Finland (YYYY-MM-DD), checked on every row. Tori lists newest first, so the newer ads in front are read and left out free; a day far back can stop the run on its allowance for unpaid reads."
          },
          "includeKeywords": {
            "title": "Must contain",
            "type": "array",
            "description": "Words an ad must contain (its title, and its description when the ad page is read). Any one of them, or all with requireAllKeywords.",
            "items": {
              "type": "string"
            }
          },
          "requireAllKeywords": {
            "title": "Require all words",
            "type": "boolean",
            "description": "With includeKeywords: every word must be in the ad.",
            "default": false
          },
          "excludeKeywords": {
            "title": "Must not contain",
            "type": "array",
            "description": "Ads holding any of these words are left out, free.",
            "items": {
              "type": "string"
            }
          },
          "titleOnly": {
            "title": "Look in titles only",
            "type": "boolean",
            "description": "includeKeywords and excludeKeywords look at the title only.",
            "default": false
          },
          "onlyKeywordMatches": {
            "title": "Only ads that carry the search words",
            "type": "boolean",
            "description": "Searches made from keywords (and pasted search links with words): deliver only the ads whose title carries every word of the search, or, when the ad page is read, its title or description. Tori's own search ends a keyword's results with ads that carry none of the words (on the last pages of a search most titles lack them); those are left out, free, and counted on the coverage row. Words are matched as parts of words (\"sohva\" matches \"kulmasohva\"); \"a OR b\" means either. Off: every ad Tori's search returns.",
            "default": true
          },
          "excludeAdIds": {
            "title": "Exclude Tori ad ids",
            "type": "array",
            "description": "Tori ad ids (Ilmoituksen tunnus) or ad links never to deliver.",
            "items": {
              "type": "string"
            }
          },
          "searchUrls": {
            "title": "Search links",
            "type": "array",
            "description": "Search pages copied from Tori (https://www.tori.fi/recommerce/forsale/search?...), read with all their filters. Tori's sort order in a link is not sent (Tori asks robots not to); the link is read in Tori's default order.",
            "items": {
              "type": "string"
            }
          },
          "adUrls": {
            "title": "Ad links or Tori ad ids",
            "type": "array",
            "description": "Tori ad links (https://www.tori.fi/recommerce/forsale/item/<id> or https://www.tori.fi/<id>) or Tori ad ids (Ilmoituksen tunnus): each read with its ad page and billed as one Listing plus one Ad details. A removed or unknown ad is a free row.",
            "items": {
              "type": "string"
            }
          },
          "maxItems": {
            "title": "Maximum rows",
            "minimum": 1,
            "maximum": 200000,
            "type": "integer",
            "description": "The most paid rows (ads) the run delivers, across all searches and links.",
            "default": 100
          },
          "maxItemsPerSearch": {
            "title": "Maximum rows per search",
            "minimum": 1,
            "maximum": 200000,
            "type": "integer",
            "description": "The most paid rows from one search or search link."
          },
          "maxPagesPerSearch": {
            "title": "Maximum pages per search",
            "minimum": 1,
            "maximum": 20000,
            "type": "integer",
            "description": "The most result pages read for one search."
          },
          "maxRowsPerSearch": {
            "title": "Rows read per search",
            "minimum": 1,
            "maximum": 200000,
            "type": "integer",
            "description": "How many rows of each search are read at most, the rows left out by a filter included (no limit by default)."
          },
          "startPage": {
            "title": "Start page",
            "minimum": 1,
            "maximum": 50,
            "type": "integer",
            "description": "Read every search from this page of Tori's own results (53 ads a page) instead of the first: to go on from where an earlier run stopped. Such a search is not split past Tori's 50 page reach and its coverage row says it is not complete. Given, even as 1, every search is read in Tori's own pages from that page, so runs of startPage 1, 2, 3 never overlap."
          },
          "includeDetails": {
            "title": "Include the ad page (Ad details)",
            "type": "boolean",
            "description": "Read each ad's page: the full description, every attribute (condition, size, material, brand) and all images, the category path, the postal code and street (a company's), the edited time, and a shop's profile (name, address, phone, website, business id Y-tunnus, its shop page). Billed as one Ad details per row that carries its ad page; about a second per row.",
            "default": false
          },
          "includePersonalData": {
            "title": "Include personal data",
            "type": "boolean",
            "description": "Deliver the fields that name or reach a private person: a private seller's Tori user id, the street and exact map point of a private seller's ad (off: the point is rounded to 2 decimals, about 1 km, when Tori gives it to the address), and the contacts found in the texts of private ads. Tori shows no private seller's name to visitors who are not logged in, so no name is delivered. Off: those fields are empty; a company's name, id, business id (Y-tunnus), address, phone and website are business data and always delivered. You are responsible for a lawful use, GDPR included.",
            "default": false
          },
          "markPaidPlacements": {
            "title": "Mark paid placements",
            "type": "boolean",
            "description": "Read the paid ad Tori shows above each search's results (one small extra read per search, free) and flag each delivered row that is one (paidPlacement true or false); the search's coverage row names the paid ad and whether it stood among its results. A paid ad that is not among the results is not delivered (its own row cannot prove the search's filters). Ad links and shop stocks say null.",
            "default": false
          },
          "priceSummary": {
            "title": "Price summary per search",
            "type": "boolean",
            "description": "Each search's coverage row carries the count, lowest, quartiles, median, mean and highest asking price of the ads it met, and per Tori region and per category their count, median, lowest, highest and mean. Free.",
            "default": true
          },
          "includeRawData": {
            "title": "Include raw search row",
            "type": "boolean",
            "description": "Add Tori's search row as served (a private seller's only with personal data on).",
            "default": false
          },
          "descriptionFormat": {
            "title": "Description format",
            "enum": [
              "asServed",
              "text",
              "markdown"
            ],
            "type": "string",
            "description": "How the ad description is delivered.",
            "default": "asServed"
          },
          "descriptionMaxLength": {
            "title": "Description maximum length",
            "minimum": 20,
            "maximum": 100000,
            "type": "integer",
            "description": "Cut descriptions to this many characters (descriptionCut marks the row)."
          },
          "outputFields": {
            "title": "Fields to keep",
            "type": "array",
            "description": "Keep only these row fields, by the names the rows carry (\"adId\", \"url\", \"region\", \"municipality\", \"companyName\", \"attributesById\"); the row's identity, title, price, place, status and image count always stay. Not together with compactOutput.",
            "items": {
              "type": "string"
            }
          },
          "compactOutput": {
            "title": "Compact rows",
            "type": "boolean",
            "description": "Deliver only the most used fields (handy for AI agents).",
            "default": false
          },
          "excludeEmptyFields": {
            "title": "Leave out empty fields",
            "type": "boolean",
            "description": "Drop fields that are empty on a row.",
            "default": false
          },
          "extractContacts": {
            "title": "Extract contacts from texts",
            "type": "boolean",
            "description": "Add the e-mail addresses, phone numbers, websites and social profiles written in the title and description (companies' ads always; private ads with includePersonalData on).",
            "default": false
          },
          "phoneExtractionMode": {
            "title": "Phone extraction",
            "enum": [
              "strict",
              "lenient"
            ],
            "type": "string",
            "description": "With extractContacts."
          },
          "failIfIncomplete": {
            "title": "Fail if incomplete",
            "type": "boolean",
            "description": "End the run as failed when a search or link could not be read in full (the rows delivered stay).",
            "default": false
          },
          "maxFailedRequestsPercent": {
            "title": "Fail above this share of failed reads (%)",
            "minimum": 1,
            "maximum": 100,
            "type": "integer",
            "description": "End the run as failed when more of its reads failed."
          },
          "completenessTolerancePercent": {
            "title": "Complete within this share of Tori's count (%)",
            "minimum": 0,
            "maximum": 50,
            "type": "number",
            "description": "Your own bar for a complete search: a search counts as complete when it met at least Tori's count of ads less this percent (and less the number of ads below). Empty: the fixed rule (98 percent of Tori's count less 2 ads on a split search, 99 percent less 2 on one search)."
          },
          "completenessToleranceAbsolute": {
            "title": "Complete within this many ads of Tori's count",
            "minimum": 0,
            "maximum": 100000,
            "type": "integer",
            "description": "Your own bar for a complete search, in ads: Tori's count less this many ads (and less the percent above). Empty: the fixed rule."
          },
          "proxyConfiguration": {
            "title": "Proxy",
            "type": "object",
            "description": "Leave as is: Tori is read through Apify's datacenter proxy, which every Tori door answers. Your own proxy links replace it."
          },
          "requestsPerSecond": {
            "title": "Requests per second",
            "minimum": 0.2,
            "maximum": 2,
            "type": "number",
            "description": "The pace of the run's one exit (0.2 to 2).",
            "default": 1
          },
          "maxConcurrency": {
            "title": "Requests in flight",
            "minimum": 1,
            "maximum": 4,
            "type": "integer",
            "description": "At most this many requests in flight, inside the pace (Tori is never asked more than requestsPerSecond requests a second): ad pages are read on this many lanes.",
            "default": 4
          },
          "maxRequestRetries": {
            "title": "Retries",
            "minimum": 0,
            "maximum": 5,
            "type": "integer",
            "description": "Tries of a failed read after the first.",
            "default": 2
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}