{
  "openapi": "3.0.1",
  "info": {
    "title": "Vinted Price Monitor: Price Drop Alerts Without Login",
    "description": "Vinted price monitor: schedule a saved search and get back only the listings that got cheaper since the last run, with the old price, the new price and the drop percentage. Price drop alerts to Discord, Slack or Telegram. 27 countries, no login. A quiet run with nothing cheaper is free.",
    "version": "1.0",
    "x-build-id": "Mf5ygRTNHlEABPsVs"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/accountable_eel~vinted-price-monitor/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-accountable_eel-vinted-price-monitor",
        "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/accountable_eel~vinted-price-monitor/runs": {
      "post": {
        "operationId": "runs-sync-accountable_eel-vinted-price-monitor",
        "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/accountable_eel~vinted-price-monitor/run-sync": {
      "post": {
        "operationId": "run-sync-accountable_eel-vinted-price-monitor",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "required": [
          "searches"
        ],
        "properties": {
          "searches": {
            "title": "Vinted searches to watch for price drops",
            "type": "array",
            "description": "One search per line: plain keywords such as \"carhartt jacket\", or a search link copied from your browser on any Vinted country site (its own filters such as brand, size and category are kept). Each line becomes a watchlist: the first run remembers the prices it finds, and every run after it returns only the listings that got cheaper. Keywords run once in every country you pick below; a pasted link runs on its own country site. No login required. Accepted formats: carhartt, levis 501, https://www.vinted.fr/catalog?search_text=stone%20island&order=newest_first. You're only charged for the ones we actually find — a miss costs nothing.",
            "items": {
              "type": "string"
            }
          },
          "countries": {
            "title": "Vinted countries to watch",
            "type": "array",
            "description": "One country code per line. Keywords run once in each: fr, de, it, es, nl, be, at, pl, cz, sk, lt, lu, pt, uk, ie, se, fi, dk, hu, ro, hr, gr, ee, lv, si, us (vinted.com) and au (vinted.com.au). Prices come back in each site's own currency plus a euro conversion. Ignored for pasted Vinted links, which use their own country. Leave empty for France.",
            "items": {
              "type": "string"
            }
          },
          "testRun": {
            "title": "Try it first — only process the first 5",
            "type": "boolean",
            "description": "Turn this on to test your input on a small sample before running the full list. Turn it off to process everything.",
            "default": false
          },
          "onlyFound": {
            "title": "Hide rows with no result",
            "type": "boolean",
            "description": "Only keep rows where something was actually found. Misses are always free, whether or not you show them here.",
            "default": false
          },
          "includeKeywords": {
            "title": "Only keep rows containing",
            "type": "array",
            "description": "Optional. Only keep results that mention at least one of these words (e.g. a job title, a city, a product name). Leave empty to keep everything.",
            "items": {
              "type": "string"
            }
          },
          "excludeKeywords": {
            "title": "Skip rows containing",
            "type": "array",
            "description": "Optional. Drop any result that mentions one of these words. Leave empty to skip nothing.",
            "items": {
              "type": "string"
            }
          },
          "maxResults": {
            "title": "Stop after this many results",
            "minimum": 1,
            "type": "integer",
            "description": "Optional. Stop the run once this many results have been found — useful for a quick, cheap sample. Leave blank for no limit."
          },
          "maxListingsPerSearch": {
            "title": "Most listings to check per search, per country",
            "type": "integer",
            "description": "Vinted shows 96 listings per page and stops any single search at 960. Above 960 (up to 2,000) this actor splits the search into price bands and merges them newest first. This is how deep the watchlist looks, not how many rows you get back: you only pay for the listings that actually got cheaper.",
            "default": 96
          },
          "minPrice": {
            "title": "Minimum price (each country's own currency)",
            "type": "integer",
            "description": "Optional. Sent to Vinted as its own price filter, on the item price before the buyer protection fee. On a multi-country run it applies in each site's currency (euros on vinted.fr, zloty on vinted.pl)."
          },
          "maxPrice": {
            "title": "Maximum price (each country's own currency)",
            "type": "integer",
            "description": "Optional. Sent to Vinted as its own price filter, on the item price before the buyer protection fee. Leave empty for no maximum."
          },
          "conditions": {
            "title": "Conditions to keep (optional)",
            "type": "array",
            "description": "Optional. One per line: new_with_tags, new, like_new, good, fair, unknown. Leave empty to keep every condition. Matched against Vinted's own 5 grades (New with tags, New without tags, Very good, Good, Satisfactory) in whichever of the 27 site languages this listing came from; a listing this actor could not match to a known label is `unknown` — never a guessed grade. Applied while paging, so the actor keeps reading pages until it has enough matching listings.",
            "items": {
              "type": "string"
            }
          },
          "brands": {
            "title": "Brands (name filter, optional)",
            "type": "array",
            "description": "Optional. Keep only listings whose brand contains one of these names (case-insensitive, e.g. \"Carhartt\"). Checked against the brand this run already returns — no extra request.",
            "items": {
              "type": "string"
            }
          },
          "deltaMode": {
            "title": "Only return listings that got cheaper since the last run",
            "type": "boolean",
            "description": "On by default: this is what the actor is for. The first run remembers every listing and price it finds and returns a single summary row. From the second run on, a listing comes back only when its price has fallen by at least the percentage below since it was last seen, with the old price, the new price and the drop percentage on the row. Unchanged listings are removed before you are billed, so a quiet run only costs the start fee. Schedule it every 10 minutes or hourly, and have each drop posted straight to Discord, Slack or Telegram with \"Send alerts to\" below. Turn this off to get every matching listing instead, like an ordinary search.",
            "default": true
          },
          "deltaName": {
            "title": "Watchlist name (optional)",
            "type": "string",
            "description": "Leave empty and one is derived from this run's price filters, so two schedules with different filters keep separate price memories. Type your own name to keep one memory across a filter change.",
            "default": ""
          },
          "minPriceDropPct": {
            "title": "Smallest price drop worth an alert (%)",
            "type": "integer",
            "description": "A listing must be at least this much cheaper than when it was last seen to come back as a price drop. 5 means a 20 euro item has to fall by at least 1 euro. Raise it to only hear about real cuts.",
            "default": 5
          },
          "alertOnPriceDrop": {
            "title": "Alert on price drops",
            "type": "boolean",
            "description": "On by default. The drop is measured on the item price, not the total with the buyer protection fee. Turning this off with the checkbox above on leaves nothing to return.",
            "default": true
          },
          "alertOnNew": {
            "title": "Also return listings that are brand new",
            "type": "boolean",
            "description": "Off by default, so your results stay price drops only. Turn it on to also get listings this watchlist has never seen, each marked new rather than price-drop. They are billed like any other row.",
            "default": false
          },
          "skipFirstRun": {
            "title": "Seed silently (no rows on the first run)",
            "type": "boolean",
            "description": "The first run of a watchlist has no earlier price to compare with, so it returns one summary row and no listings either way. This matters only if you also turned on \"Also return listings that are brand new\": with it on, the first run remembers everything silently instead of returning a hundred rows at once.",
            "default": false
          },
          "quietRunOutput": {
            "title": "What a run with no price drops writes to the results",
            "enum": [
              "summary",
              "none"
            ],
            "type": "string",
            "description": "A quiet run is a search with nothing cheaper since the last run. \"One summary row\" (the default) keeps the row with monitorStatus NO_NEW_ROWS and zero listings. \"Nothing\" writes zero items, so a bot or integration reading the results never has to skip rows. A search that failed still returns its error row.",
            "default": "summary"
          },
          "notifyUrl": {
            "title": "Send alerts to (Discord or Slack webhook, Telegram bot link, or any URL)",
            "type": "string",
            "description": "Optional. After the price drops are billed, each one is posted here as one message: photo, title, the old and new price, size, condition, country and link, with a PRICE DROP -X% badge. Discord or Slack: paste the channel's webhook URL. Telegram: https://api.telegram.org/bot<token>/sendMessage?chat_id=<chat id>. Any other URL receives JSON. Messages are free, and a message that fails never fails the run (the row's notifyErrors says why). Stored encrypted, never logged or written to the results."
          },
          "notifyFormat": {
            "title": "Message format",
            "enum": [
              "auto",
              "discord",
              "slack",
              "telegram",
              "json"
            ],
            "type": "string",
            "description": "Leave on \"Detect from the link\": discord.com links get Discord messages, hooks.slack.com Slack, api.telegram.org Telegram, anything else JSON. Pick one only to override that.",
            "default": "auto"
          },
          "maxNotificationsPerRun": {
            "title": "Most alert messages per run",
            "type": "integer",
            "description": "Up to 100. Above this, one \"+N more\" message says how many more price drops are in the run's results, so a busy run never floods the channel. 0 sends only that one summary message.",
            "default": 20
          },
          "columns": {
            "title": "Which columns do you want?",
            "type": "array",
            "description": "Choose which pieces of information to include in each result row. All are included by default.",
            "items": {
              "type": "string",
              "enum": [
                "searchQuery",
                "searchCountries",
                "listingCount",
                "priceDropCount",
                "monitorStatus",
                "medianPriceEur",
                "listings",
                "listingId",
                "title",
                "price",
                "previousPrice",
                "priceDropPct",
                "totalPrice",
                "currency",
                "priceEur",
                "countryMedianPriceEur",
                "priceGapPct",
                "brand",
                "size",
                "condition",
                "conditionRaw",
                "conditionBucket",
                "country",
                "favouriteCount",
                "sellerType",
                "imageUrl",
                "url",
                "changeType",
                "firstSeenAt",
                "lastSeenAt",
                "daysListed"
              ],
              "enumTitles": [
                "Search",
                "Countries searched",
                "Price drops returned",
                "Price drops since last run",
                "Monitoring status",
                "Median price of the search, EUR",
                "All price drops found (full list)",
                "Vinted listing ID",
                "Title",
                "Price (local currency)",
                "Price when last seen",
                "Price drop %",
                "Price incl. buyer protection fee",
                "Currency",
                "Price in EUR (ECB daily rate)",
                "Median price in this country, EUR",
                "Cross-country price gap % (vs median of all countries)",
                "Brand",
                "Size",
                "Condition",
                "Condition (raw label)",
                "Condition (standard grade)",
                "Vinted country",
                "Favourites",
                "Seller type (private / business)",
                "Main photo",
                "Listing link",
                "Change (new / price-drop / gone / seen)",
                "First seen on a run",
                "Last seen on a run",
                "Days listed (first to last seen)"
              ]
            },
            "default": [
              "searchQuery",
              "searchCountries",
              "listingCount",
              "priceDropCount",
              "monitorStatus",
              "medianPriceEur",
              "listings",
              "listingId",
              "title",
              "price",
              "previousPrice",
              "priceDropPct",
              "totalPrice",
              "currency",
              "priceEur",
              "countryMedianPriceEur",
              "priceGapPct",
              "brand",
              "size",
              "condition",
              "conditionRaw",
              "conditionBucket",
              "country",
              "favouriteCount",
              "sellerType",
              "imageUrl",
              "url",
              "changeType",
              "firstSeenAt",
              "lastSeenAt",
              "daysListed"
            ]
          },
          "expandRows": {
            "title": "One row per listing (recommended) — turn off for one row per search instead",
            "type": "boolean",
            "description": "When on, each listing found gets its own row instead of being grouped under its search. You're still only charged once per search, no matter how many rows it produces.",
            "default": true
          },
          "residentialFallback": {
            "title": "Retry refused pages on a residential connection",
            "type": "boolean",
            "description": "On by default. Vinted sometimes refuses Apify's shared datacenter connections on a country site (seen on vinted.de). The actor first retries on fresh datacenter connections, then on a residential one, for that page only. It costs you nothing extra: you still pay per listing returned. Turn it off to never use residential connections.",
            "default": true
          },
          "maxConcurrency": {
            "title": "Max concurrency",
            "minimum": 1,
            "maximum": 10,
            "type": "integer",
            "description": "Parallel requests. Keep conservative — this target has no browser fallback, so getting blocked costs more than slow-and-steady.",
            "default": 3
          },
          "proxyConfiguration": {
            "title": "Proxy configuration",
            "type": "object",
            "description": "Apify Proxy config. Residential recommended for anti-bot-sensitive targets.",
            "default": {
              "useApifyProxy": true
            }
          }
        }
      },
      "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
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}