# Vinted Demand & Sell-Through Scraper (`unfenced-group/vinted-arbitrage-scanner`) Actor

Vinted demand intelligence: sell-through rate, realised sale prices, days-to-sell, and cross-market sourcing. No proxy, no PII.

- **URL**: https://apify.com/unfenced-group/vinted-arbitrage-scanner.md
- **Developed by:** [Unfenced Group](https://apify.com/unfenced-group) (community)
- **Categories:** E-commerce, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.78 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Vinted Demand & Sell-Through Scraper

Most Vinted scrapers tell you what's *listed*. This one tells you what actually **sells** — at what price, and how fast.

Run it on a schedule and it tracks your niche over time: which items disappear (sold), what they really went for, how many days they took, and which price bands move quickest. On top of that it does cross-market sourcing — find the cheapest listings for a product across up to 26 markets in one run, every price normalised to one currency.

Built for resellers who want to validate demand *before* they buy, not just pull a list of listings.

![Vinted Demand & Sell-Through Scraper](https://api.apify.com/v2/key-value-stores/lJlifu6C8YQfZMPKE/records/vinted-arbitrage-scanner-banner.png)

### Why this over other Vinted scrapers

Other Vinted scrapers extract listings. A few add a cross-country "arbitrage" comparison. This actor does what actually drives sourcing decisions, and is honest about what works:

- **Real sell-through, not just listings.** Vinted has no "sold" flag — sold items simply vanish. By tracking your niche across scheduled runs, this actor reports a true sell-through rate, median days-to-sell, and per-item sold detection. Other scrapers can't tell you whether anything actually sells.
- **Realised sale prices.** When an item sells, you get its last price before it disappeared — the median, min, max, and average of what items *actually went for*. Listing prices tell you what sellers hope for; this tells you what the market pays.
- **Velocity by price band.** See which price points move fastest (e.g. under-€20 in 3 days vs €50-100 in 12), so you source what turns over.
- **Price-drop detection.** Flags still-listed items whose seller cut the price since the last run — a signal of stock that isn't moving. Folded into the same run, not a separate paid mode.
- **Honest cross-market sourcing.** Two things people confuse: a single *listing* (one seller's specific item) has the same price in every Vinted market it ships to — so there's no "buy the same listing cheaper abroad" arbitrage, contrary to what "arbitrage" scrapers imply (we verified this). But a *product* — say a black Nike Air Force 1 in size 42 — is sold by many different sellers at many different prices. The real edge is scanning all those sellers across every market in one run to find the genuinely underpriced ones, plus benchmarking what the product typically goes for. This actor surfaces that without overclaiming a price gap that isn't there.
- **Real buyer-paid price.** Every listing carries `buyerPrice` — the total including Vinted's Buyer Protection fee, the number that actually decides a flip. Most scrapers omit it.
- **No proxy required, no PII.** Direct connection, listing data only — no seller names, profiles, or personal data.

### What it does

- **Sell-through tracking.** Scheduled snapshot comparison surfaces what sold, what it sold for, and how fast — the core demand signal. (See the dedicated section below.)
- **Cross-market sourcing.** Search one query across multiple Vinted markets at once, every price converted to your comparison currency via live ECB rates, deduplicated so the same cross-listed item appears once with the markets it ships to.
- **Every Vinted category, not just clothing.** Search fashion (women/men/kids) *or* Home, Electronics & Entertainment, Video Games, Books & Media, Beauty & Hair, Jewellery, Sports & Footwear, Phone Accessories, and Bags — the whole marketplace, one actor.
- **Rich filters.** Department, category, colour, clothing/shoe/kids sizes, condition, brand, and price range — all server-side.
- **Demand signals.** Favourite counts on every listing.
- **No item cap.** Up to ~960 listings per market per query (Vinted's ceiling), across as many markets as you select.
- **Alerts.** Push sell-through summaries or sourcing results to Telegram, Discord, or Slack.


### Pricing

**$0.80 per 1,000 results** ($0.0008 per result), tiered down to $0.76/1,000 at the DIAMOND plan. A small **$0.001 per run** start fee also applies (charged per GB of memory at run start, minimum one), which keeps tiny test runs essentially free. No subscription — you pay per use.

With **Fetch full item details** enabled, results are billed at **$1.29 per 1,000** instead — this fetches each listing's page for the seller's description, declared colour, and full category path (data the fast search API doesn't expose).

### Input

| Field | Type | Description |
|---|---|---|
| `searchQuery` | string | Product, brand, or model to scan (e.g. `nike air force 1`). |
| `countries` | array | Markets to compare. Default: FR, DE, NL, IT, ES. 26 markets available. |
| `maxResults` | integer | Total listings across all markets (split evenly). Default 100. |
| `baseCurrency` | string | Currency all markets convert to for comparison. Default EUR. |
| `sortBy` | string | `relevance`, `price_low_to_high`, `price_high_to_low`, `newest_first`. |
| `priceMin` / `priceMax` | integer | Price bounds in each market's local currency. |
| `condition` | array | Filter by condition (new with tags, very good, etc.). |
| `brandNames` | array | Filter by brand — type names like "Nike", "Stone Island"; IDs are looked up automatically. |
| `brandIds` | array | Advanced: raw Vinted brand ID if you already know it. |
| `clothingSizes` | array | Filter by clothing size (XS–XXXL). |
| `shoeSizes` | array | Filter by EU shoe size (38–47.5). |
| `sizeIds` | array | Advanced: raw Vinted size ID for other categories. |
| `colors` | array | Filter by colour (black, white, red, blue, etc.). Narrows the scan; not added as an output field — Vinted doesn't return a colour per listing. |
| `gender` | string | Department: All, Women, Men, Kids. |
| `category` | string | Verified category: Shoes, Coats & Jackets, Dresses, Bags, Men's Jeans. Overrides gender. |
| `categoryId` | integer | Advanced: raw Vinted catalog ID for any other category. |
| `includeListings` | boolean | Output every listing row. Default true. |
| `fetchDetails` | boolean | Fetch each listing's description, declared colour, and full category path (slower; billed at the premium $1.29/1k rate). Default off. |
| `includeArbitrageSummary` | boolean | Output the cross-country summary row. Default true. |

### Output

#### Listing rows (always present when `includeListings` is on)

| Field | Type | Description |
|---|---|---|
| `id` | string | Vinted listing ID. |
| `country` | string | Market the listing was found in. |
| `description` | string | (fetchDetails only) Seller's free-text description — measurements, flaws, authenticity notes. |
| `declaredColor` | string | (fetchDetails only) The colour the seller declared (not in the search API). |
| `categoryPath` | string | (fetchDetails only) Full category path, e.g. "Men > Windbreaker Jackets". |
| `markets` | array | Every market this exact item was found in (cross-market duplicates are merged into one row). |
| `url` | string | Direct listing URL. |
| `title` | string | Listing title. |
| `brand` | string \| null | Brand name. |
| `size` | string \| null | Size label. |
| `condition` | string \| null | Item condition. |
| `currency` | string | Local currency of the listing. |
| `itemPrice` | number | Seller's asking price (local currency). |
| `buyerPrice` | number | Total the buyer pays incl. Buyer Protection (local currency). |
| `serviceFee` | number \| null | Buyer Protection fee (local currency). |
| `itemPriceBase` | number \| null | Asking price converted to your comparison currency. |
| `buyerPriceBase` | number \| null | Buyer-paid price converted to your comparison currency. |
| `baseCurrency` | string | The comparison currency. |
| `favouriteCount` | number \| null | Number of favourites (demand signal). |
| `isPromoted` | boolean | Whether the listing is a promoted/bumped item. |
| `isBusinessSeller` | boolean \| null | Whether the seller is a registered business (vs private individual). No seller identity is collected. |
| `photoCount` | number | Number of photos on the listing. |
| `photoUrl` | string \| null | Primary product photo. |
| `dominantColor` | string \| null | Dominant colour of the primary photo (hex). |
| `photoUploadedAt` | string \| null | Approximate listing-creation time (primary image upload, ISO). |

#### Arbitrage summary row (when `includeArbitrageSummary` is on)

| Field | Description |
|---|---|
| `buyLowMarket` | Market with the lowest median price. |
| `sellHighMarket` | Market with the highest median price. |
| `medianSpread` | Median price gap between them (comparison currency). |
| `medianSpreadPct` | The same gap as a percentage. |
| `perMarket` | Per-market min / median / average / max and sample size. |

#### Example output

```json
{
  "id": "9214402685",
  "country": "uk",
  "url": "https://www.vinted.co.uk/items/9214402685-nike-air-force-1",
  "title": "Nike Air Force 1 white",
  "brand": "Nike",
  "size": "UK 7",
  "condition": "Very good",
  "currency": "GBP",
  "itemPrice": 22,
  "buyerPrice": 24.35,
  "serviceFee": 2.35,
  "itemPriceBase": 25.39,
  "buyerPriceBase": 28.1,
  "baseCurrency": "EUR",
  "favouriteCount": 34,
  "isBusinessSeller": false,
  "photoCount": 5,
  "isPromoted": false,
  "photoUrl": "https://images1.vinted.net/t/.../f800/....jpeg",
  "dominantColor": "#B58D86",
  "photoUploadedAt": "2026-06-19T14:22:05.000Z"
}
````

```json
{
  "_type": "ARBITRAGE_SUMMARY",
  "query": "nike air force 1",
  "baseCurrency": "EUR",
  "buyLowMarket": "uk",
  "sellHighMarket": "fr",
  "medianSpread": 29.04,
  "medianSpreadPct": 111.9,
  "perMarket": [
    { "country": "uk", "currency": "GBP", "sampleSize": 20, "minPrice": 1.73, "medianPrice": 25.96, "avgPrice": 28.4, "maxPrice": 103.86 },
    { "country": "fr", "currency": "EUR", "sampleSize": 20, "minPrice": 8, "medianPrice": 55, "avgPrice": 52.1, "maxPrice": 90 }
  ]
}
```

### Examples

**1. Scan a sneaker across five markets**

```json
{
  "searchQuery": "nike air force 1",
  "countries": ["fr", "de", "uk", "it", "es"],
  "maxResults": 250,
  "baseCurrency": "EUR"
}
```

**2. Find the cheapest market for a brand, new-with-tags only**

```json
{
  "searchQuery": "ralph lauren shirt",
  "countries": ["uk", "pl", "ro", "lt"],
  "condition": ["new_with_tags"],
  "sortBy": "price_low_to_high",
  "maxResults": 200
}
```

**3. Brand-filtered scan with a price ceiling**

```json
{
  "searchQuery": "jacket",
  "brandIds": ["53"],
  "priceMax": 40,
  "countries": ["fr", "de", "be", "nl"],
  "baseCurrency": "EUR",
  "maxResults": 300
}
```

**4. Summary only — a daily market map with no listing rows**

```json
{
  "searchQuery": "carhartt",
  "countries": ["fr", "de", "uk", "it", "es", "pl"],
  "includeListings": false,
  "includeArbitrageSummary": true
}
```

### Notes

- Vinted caps any single search at roughly 960 results per market. The scanner paginates up to that ceiling per market and stops cleanly.
- Prices are normalised with live European Central Bank reference rates, refreshed each run. Treat converted figures as indicative — actual FX at checkout varies.
- This actor reads publicly visible listing data only. It does not collect seller names, profile pages, or any personal data, and it does not log in, transact, or interact with the marketplace.

### Alerts (Telegram, Discord, Slack)

Schedule this actor and have arbitrage opportunities pushed to you automatically — no need to log in and check the dataset. Configure any combination of the three channels; alerts are optional and never block a run.

Each alert contains the cross-country arbitrage summary (buy-low / sell-high markets and the spread) plus the cheapest listings found.

| Field | What to enter |
|---|---|
| `telegramBotToken` + `telegramChatId` | Create a bot with @BotFather, paste its token and the target chat/channel ID. |
| `discordWebhookUrl` | A Discord Incoming Webhook URL (Server Settings → Integrations → Webhooks). |
| `slackWebhookUrl` | A Slack Incoming Webhook URL. |
| `minSpreadPctAlert` | Only alert when the median spread is at least this %. Leave empty to always alert. |
| `alertTopListings` | How many of the cheapest listings to include per alert (default 5). |

Pair this with Apify's scheduler to get, for example, a daily Telegram ping listing the best cross-border flips for your niche — but only when the spread is worth acting on.

### Sell-through tracking — measure real demand

The most valuable signal for a reseller isn't what's listed — it's what actually **sells**. Vinted has no "sold" marker (sold items just vanish), so this mode works by comparison: run it on a schedule, and the actor snapshots the live listings each time. Items that disappear are flagged `likely_sold`, giving you a real sell-through rate and median days-to-sell for your niche.

Turn on `sellThroughTracking`, give it a stable `trackerName`, and schedule it (daily works well). The first run records a baseline; every run after that reports what sold.

| Field | What it does |
|---|---|
| `sellThroughTracking` | Switches the actor into tracking mode. |
| `trackerName` | Stable name so history accumulates across scheduled runs. Reuse the same value. |
| `missingRunsBeforeSold` | Consecutive runs an item must be absent before it counts as sold (2 avoids false positives). |
| `emitActiveItems` | Also output still-listed items, with days-listed. |

Each run outputs a `SELL_THROUGH_SUMMARY` plus per-item rows. The summary goes beyond a simple sold count:

- `sellThroughRatePct`, `likelySold`, `stillActive`, `newItems`
- `realisedPrice` — median/min/max/avg of what sold items **actually went for** (their last price before disappearing), not listing prices
- `medianDaysToSell` and `velocityByPriceBand` — how fast items sell, segmented by price band (e.g. under-€20 vs €50-100)
- `soldByCondition` — which conditions move
- `priceDrops` — still-listed items whose seller cut the price since last run (a signal of stock that isn't moving)

Optionally send a sell-through alert to Telegram/Discord/Slack each run, gated by `minSellThroughAlertPct` so you're only pinged when a niche is genuinely moving.

Use it to validate demand before you buy: a niche with a high sell-through rate, low days-to-sell, and a healthy realised price is one worth sourcing.

***

### Need a custom scraper?

**[Unfenced Group](https://www.unfencedgroup.nl)** builds Apify actors for any website — for free.

If the site you need isn't in our portfolio yet, just ask. We scope, build, and publish it at no cost to you. You only pay for results — we absorb the compute and proxy costs ourselves. Same pay-per-result pricing, same quality, same standards as every actor in this portfolio.

**Get in touch:** [www.unfencedgroup.nl](https://www.unfencedgroup.nl)

# Actor input Schema

## `searchQuery` (type: `string`):

Product, brand, or model to scan across markets (e.g. 'nike air force 1', 'ralph lauren jumper').

## `countries` (type: `array`):

Vinted markets to scan. Pick 2-5 for a focused arbitrage scan. All listings are normalised to one currency for comparison.

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

Total listings to return across all markets (split evenly). Vinted caps each query at ~960 per market.

## `baseCurrency` (type: `string`):

Currency all markets are converted to for price-gap comparison. Live ECB rates.

## `sortBy` (type: `string`):

How listings are ordered within each market.

## `priceMin` (type: `integer`):

Minimum listing price in each market's local currency. Leave empty for no minimum.

## `priceMax` (type: `integer`):

Maximum listing price in each market's local currency. Leave empty for no maximum.

## `condition` (type: `array`):

Filter by item condition. Leave empty to include all conditions.

## `brandNames` (type: `array`):

Filter by brand — just type the names (e.g. 'Nike', 'Stone Island'). The actor looks up each brand's ID automatically. Leave empty for all brands.

## `brandIds` (type: `array`):

Advanced: filter by raw Vinted brand ID if you already know it. Most users should use Brand names above instead.

## `sizeIds` (type: `array`):

Advanced: filter by raw Vinted size ID for categories not covered by the dropdowns below. Find it in the URL after selecting a size filter. Leave empty for all sizes.

## `clothingSizes` (type: `array`):

Filter by clothing size (XS–XXXL). For shoes, use the shoe size filter below. Leave empty for all sizes.

## `shoeSizes` (type: `array`):

Filter by EU shoe size (38–47.5). For clothing, use the clothing size filter above. Leave empty for all sizes.

## `kidsSizes` (type: `array`):

Filter by kids clothing size (age / cm, e.g. '6 yr / 116 cm'). Covers newborn to 16 years. Leave empty for all sizes.

## `colors` (type: `array`):

Filter listings by colour. Leave empty for all colours. Note: Vinted does not return a colour value per listing, so this narrows the scan but does not add a colour output field.

## `gender` (type: `string`):

Filter by department. Vinted sells far more than clothing — pick Home, Electronics, Video Games, Books & Media, Beauty, Jewellery, Sports, or Bags for non-fashion categories. Leave as 'All' to search everything. Note: if you pick a specific Category below, that takes precedence over this.

## `category` (type: `string`):

Filter by product category. These are the verified cross-department categories. For any other category, use the advanced Category ID field below. If set, this overrides the Department filter.

## `categoryId` (type: `integer`):

Advanced: filter by a specific Vinted catalog ID not covered by the Category dropdown. Find it in the catalog URL (catalog\[]=NUMBER). Overrides Department and Category if set.

## `includeListings` (type: `boolean`):

Output every matching listing row. Disable to get only the cross-country arbitrage summary (cheaper).

## `dedupeAcrossMarkets` (type: `boolean`):

Vinted shows the same listing in every market it ships to. With this on, each item appears once, with a 'markets' field listing every market it was found in. Turn off to get one row per market.

## `fetchDetails` (type: `boolean`):

Fetch each listing's page for the seller's description, declared colour, and full category path — data not in the fast search API. This makes runs slower and is billed at a higher per-result rate. Leave off for fast, cheap catalog data.

## `sellThroughTracking` (type: `boolean`):

Measure real demand. Run this on a schedule (e.g. daily): the actor snapshots live listings and flags items that disappear as 'likely sold', giving you a sell-through rate and median days-to-sell for your niche. Overrides the normal scan output.

## `trackerName` (type: `string`):

A stable name for this sell-through tracker (e.g. 'nike-af1-kids'). Reuse the same name across scheduled runs so history accumulates. Leave empty to auto-generate from the search query.

## `missingRunsBeforeSold` (type: `integer`):

How many consecutive runs an item must be absent before it's marked likely sold. Use 2 to avoid false positives from search-ranking shuffle.

## `emitActiveItems` (type: `boolean`):

In sell-through mode, also output items that are still listed (with days-listed and any price drop). Disable to output only newly-sold items and the summary (cheaper).

## `minSellThroughAlertPct` (type: `integer`):

In sell-through mode, only send a webhook alert when the sell-through rate is at least this percentage. Leave empty to always alert. Pairs with the Telegram/Discord/Slack fields below.

## `includeArbitrageSummary` (type: `boolean`):

Add one summary row comparing median/min/max prices across markets and naming the buy-low / sell-high pair.

## `telegramBotToken` (type: `string`):

Optional. Send each run's arbitrage alert to Telegram. Create a bot with @BotFather and paste its token here. Also fill in the chat ID below.

## `telegramChatId` (type: `string`):

Optional. The chat or channel ID to send Telegram alerts to (e.g. your user ID, or -100... for a channel). Required if a bot token is set.

## `discordWebhookUrl` (type: `string`):

Optional. Send each run's arbitrage alert to a Discord channel. Paste an Incoming Webhook URL (Server Settings → Integrations → Webhooks).

## `slackWebhookUrl` (type: `string`):

Optional. Send each run's arbitrage alert to a Slack channel. Paste an Incoming Webhook URL (api.slack.com/messaging/webhooks).

## `minSpreadPctAlert` (type: `integer`):

Only send alerts when the cross-country median spread is at least this percentage. Leave empty to always alert. Useful for scheduled runs that should only ping you on real opportunities.

## `alertTopListings` (type: `integer`):

How many of the cheapest listings to include in each alert message.

## Actor input object example

```json
{
  "searchQuery": "nike air force 1",
  "countries": [
    "fr",
    "de",
    "nl",
    "it",
    "es"
  ],
  "maxResults": 100,
  "baseCurrency": "EUR",
  "sortBy": "relevance",
  "gender": "all",
  "category": "all",
  "includeListings": true,
  "dedupeAcrossMarkets": true,
  "fetchDetails": false,
  "sellThroughTracking": false,
  "missingRunsBeforeSold": 2,
  "emitActiveItems": true,
  "includeArbitrageSummary": true,
  "alertTopListings": 5
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# 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 = {
    "searchQuery": "nike air force 1"
};

// Run the Actor and wait for it to finish
const run = await client.actor("unfenced-group/vinted-arbitrage-scanner").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 = { "searchQuery": "nike air force 1" }

# Run the Actor and wait for it to finish
run = client.actor("unfenced-group/vinted-arbitrage-scanner").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 '{
  "searchQuery": "nike air force 1"
}' |
apify call unfenced-group/vinted-arbitrage-scanner --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=unfenced-group/vinted-arbitrage-scanner",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Vinted Demand & Sell-Through Scraper",
        "description": "Vinted demand intelligence: sell-through rate, realised sale prices, days-to-sell, and cross-market sourcing. No proxy, no PII.",
        "version": "0.0",
        "x-build-id": "glqhB6h8vxXGuOW2K"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/unfenced-group~vinted-arbitrage-scanner/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-unfenced-group-vinted-arbitrage-scanner",
                "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/unfenced-group~vinted-arbitrage-scanner/runs": {
            "post": {
                "operationId": "runs-sync-unfenced-group-vinted-arbitrage-scanner",
                "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/unfenced-group~vinted-arbitrage-scanner/run-sync": {
            "post": {
                "operationId": "run-sync-unfenced-group-vinted-arbitrage-scanner",
                "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": {
                    "searchQuery": {
                        "title": "🔍 Search query",
                        "type": "string",
                        "description": "Product, brand, or model to scan across markets (e.g. 'nike air force 1', 'ralph lauren jumper')."
                    },
                    "countries": {
                        "title": "🌍 Markets to compare",
                        "type": "array",
                        "description": "Vinted markets to scan. Pick 2-5 for a focused arbitrage scan. All listings are normalised to one currency for comparison.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "fr",
                                "de",
                                "uk",
                                "it",
                                "es",
                                "nl",
                                "pl",
                                "pt",
                                "be",
                                "at",
                                "lt",
                                "cz",
                                "sk",
                                "hu",
                                "ro",
                                "hr",
                                "fi",
                                "dk",
                                "se",
                                "ee",
                                "gr",
                                "ie",
                                "lu",
                                "lv",
                                "si",
                                "us"
                            ],
                            "enumTitles": [
                                "France",
                                "Germany",
                                "United Kingdom",
                                "Italy",
                                "Spain",
                                "Netherlands",
                                "Poland",
                                "Portugal",
                                "Belgium",
                                "Austria",
                                "Lithuania",
                                "Czech Republic",
                                "Slovakia",
                                "Hungary",
                                "Romania",
                                "Croatia",
                                "Finland",
                                "Denmark",
                                "Sweden",
                                "Estonia",
                                "Greece",
                                "Ireland",
                                "Luxembourg",
                                "Latvia",
                                "Slovenia",
                                "United States"
                            ]
                        },
                        "default": [
                            "fr",
                            "de",
                            "nl",
                            "it",
                            "es"
                        ]
                    },
                    "maxResults": {
                        "title": "📊 Max results (total)",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Total listings to return across all markets (split evenly). Vinted caps each query at ~960 per market.",
                        "default": 100
                    },
                    "baseCurrency": {
                        "title": "💱 Comparison currency",
                        "enum": [
                            "EUR",
                            "GBP",
                            "USD",
                            "PLN",
                            "CZK",
                            "SEK",
                            "DKK",
                            "HUF",
                            "RON"
                        ],
                        "type": "string",
                        "description": "Currency all markets are converted to for price-gap comparison. Live ECB rates.",
                        "default": "EUR"
                    },
                    "sortBy": {
                        "title": "📈 Sort by",
                        "enum": [
                            "relevance",
                            "price_low_to_high",
                            "price_high_to_low",
                            "newest_first"
                        ],
                        "type": "string",
                        "description": "How listings are ordered within each market.",
                        "default": "relevance"
                    },
                    "priceMin": {
                        "title": "💶 Min price (local currency)",
                        "type": "integer",
                        "description": "Minimum listing price in each market's local currency. Leave empty for no minimum."
                    },
                    "priceMax": {
                        "title": "💶 Max price (local currency)",
                        "type": "integer",
                        "description": "Maximum listing price in each market's local currency. Leave empty for no maximum."
                    },
                    "condition": {
                        "title": "✨ Condition filter",
                        "type": "array",
                        "description": "Filter by item condition. Leave empty to include all conditions.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "new_with_tags",
                                "new_without_tags",
                                "very_good",
                                "good",
                                "satisfactory"
                            ],
                            "enumTitles": [
                                "New with tags",
                                "New without tags",
                                "Very good",
                                "Good",
                                "Satisfactory"
                            ]
                        }
                    },
                    "brandNames": {
                        "title": "🏷️ Brand names",
                        "type": "array",
                        "description": "Filter by brand — just type the names (e.g. 'Nike', 'Stone Island'). The actor looks up each brand's ID automatically. Leave empty for all brands.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "brandIds": {
                        "title": "🏷️ Brand IDs (advanced)",
                        "type": "array",
                        "description": "Advanced: filter by raw Vinted brand ID if you already know it. Most users should use Brand names above instead.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "sizeIds": {
                        "title": "📏 Size IDs (advanced)",
                        "type": "array",
                        "description": "Advanced: filter by raw Vinted size ID for categories not covered by the dropdowns below. Find it in the URL after selecting a size filter. Leave empty for all sizes.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "clothingSizes": {
                        "title": "👕 Clothing size",
                        "type": "array",
                        "description": "Filter by clothing size (XS–XXXL). For shoes, use the shoe size filter below. Leave empty for all sizes.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "xs",
                                "s",
                                "m",
                                "l",
                                "xl",
                                "xxl",
                                "xxxl"
                            ],
                            "enumTitles": [
                                "XS",
                                "S",
                                "M",
                                "L",
                                "XL",
                                "XXL",
                                "XXXL"
                            ]
                        }
                    },
                    "shoeSizes": {
                        "title": "👟 Shoe size (EU)",
                        "type": "array",
                        "description": "Filter by EU shoe size (38–47.5). For clothing, use the clothing size filter above. Leave empty for all sizes.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "38",
                                "38.5",
                                "39",
                                "39.5",
                                "40",
                                "40.5",
                                "41",
                                "41.5",
                                "42",
                                "42.5",
                                "43",
                                "43.5",
                                "44",
                                "44.5",
                                "45",
                                "45.5",
                                "46",
                                "46.5",
                                "47",
                                "47.5"
                            ],
                            "enumTitles": [
                                "38",
                                "38.5",
                                "39",
                                "39.5",
                                "40",
                                "40.5",
                                "41",
                                "41.5",
                                "42",
                                "42.5",
                                "43",
                                "43.5",
                                "44",
                                "44.5",
                                "45",
                                "45.5",
                                "46",
                                "46.5",
                                "47",
                                "47.5"
                            ]
                        }
                    },
                    "kidsSizes": {
                        "title": "🧒 Kids size (age / cm)",
                        "type": "array",
                        "description": "Filter by kids clothing size (age / cm, e.g. '6 yr / 116 cm'). Covers newborn to 16 years. Leave empty for all sizes.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "newborn_50",
                                "1_3m_56",
                                "3_6m_62",
                                "6_9m_68",
                                "9_12m_74",
                                "12_18m_80",
                                "18_24m_86",
                                "2_3y_92",
                                "3y_98",
                                "4y_104",
                                "5y_110",
                                "6y_116",
                                "7y_122",
                                "8y_128",
                                "9y_134",
                                "10y_140",
                                "11y_146",
                                "12y_152",
                                "13y_158",
                                "14y_164",
                                "15y_170",
                                "16y_176"
                            ],
                            "enumTitles": [
                                "Up to 1m / 50 cm",
                                "1-3m / 56 cm",
                                "3-6m / 62 cm",
                                "6-9m / 68 cm",
                                "9-12m / 74 cm",
                                "12-18m / 80 cm",
                                "18-24m / 86 cm",
                                "2-3y / 92 cm",
                                "3y / 98 cm",
                                "4y / 104 cm",
                                "5y / 110 cm",
                                "6y / 116 cm",
                                "7y / 122 cm",
                                "8y / 128 cm",
                                "9y / 134 cm",
                                "10y / 140 cm",
                                "11y / 146 cm",
                                "12y / 152 cm",
                                "13y / 158 cm",
                                "14y / 164 cm",
                                "15y / 170 cm",
                                "16y / 176 cm"
                            ]
                        }
                    },
                    "colors": {
                        "title": "🎨 Colour filter",
                        "type": "array",
                        "description": "Filter listings by colour. Leave empty for all colours. Note: Vinted does not return a colour value per listing, so this narrows the scan but does not add a colour output field.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "black",
                                "white",
                                "grey",
                                "beige",
                                "brown",
                                "red",
                                "blue",
                                "navy",
                                "green",
                                "yellow",
                                "pink",
                                "purple",
                                "orange",
                                "multi"
                            ],
                            "enumTitles": [
                                "Black",
                                "White",
                                "Grey",
                                "Beige",
                                "Brown",
                                "Red",
                                "Blue",
                                "Navy",
                                "Green",
                                "Yellow",
                                "Pink",
                                "Purple",
                                "Orange",
                                "Multicolour"
                            ]
                        }
                    },
                    "gender": {
                        "title": "🚻 Department",
                        "enum": [
                            "all",
                            "women",
                            "men",
                            "kids",
                            "home",
                            "electronics",
                            "video_games",
                            "books",
                            "beauty",
                            "jewellery",
                            "sports",
                            "phone_accessories",
                            "bags"
                        ],
                        "type": "string",
                        "description": "Filter by department. Vinted sells far more than clothing — pick Home, Electronics, Video Games, Books & Media, Beauty, Jewellery, Sports, or Bags for non-fashion categories. Leave as 'All' to search everything. Note: if you pick a specific Category below, that takes precedence over this.",
                        "default": "all"
                    },
                    "category": {
                        "title": "📂 Category",
                        "enum": [
                            "all",
                            "shoes",
                            "coats_jackets",
                            "dresses",
                            "bags",
                            "mens_jeans"
                        ],
                        "type": "string",
                        "description": "Filter by product category. These are the verified cross-department categories. For any other category, use the advanced Category ID field below. If set, this overrides the Department filter.",
                        "default": "all"
                    },
                    "categoryId": {
                        "title": "📁 Category ID (advanced)",
                        "type": "integer",
                        "description": "Advanced: filter by a specific Vinted catalog ID not covered by the Category dropdown. Find it in the catalog URL (catalog[]=NUMBER). Overrides Department and Category if set."
                    },
                    "includeListings": {
                        "title": "📦 Output individual listings",
                        "type": "boolean",
                        "description": "Output every matching listing row. Disable to get only the cross-country arbitrage summary (cheaper).",
                        "default": true
                    },
                    "dedupeAcrossMarkets": {
                        "title": "🔁 Remove cross-market duplicates",
                        "type": "boolean",
                        "description": "Vinted shows the same listing in every market it ships to. With this on, each item appears once, with a 'markets' field listing every market it was found in. Turn off to get one row per market.",
                        "default": true
                    },
                    "fetchDetails": {
                        "title": "🔬 Fetch full item details (premium)",
                        "type": "boolean",
                        "description": "Fetch each listing's page for the seller's description, declared colour, and full category path — data not in the fast search API. This makes runs slower and is billed at a higher per-result rate. Leave off for fast, cheap catalog data.",
                        "default": false
                    },
                    "sellThroughTracking": {
                        "title": "📈 Sell-through tracking mode",
                        "type": "boolean",
                        "description": "Measure real demand. Run this on a schedule (e.g. daily): the actor snapshots live listings and flags items that disappear as 'likely sold', giving you a sell-through rate and median days-to-sell for your niche. Overrides the normal scan output.",
                        "default": false
                    },
                    "trackerName": {
                        "title": "🏷️ Tracker name",
                        "type": "string",
                        "description": "A stable name for this sell-through tracker (e.g. 'nike-af1-kids'). Reuse the same name across scheduled runs so history accumulates. Leave empty to auto-generate from the search query."
                    },
                    "missingRunsBeforeSold": {
                        "title": "📉 Missing runs before 'likely sold'",
                        "minimum": 1,
                        "type": "integer",
                        "description": "How many consecutive runs an item must be absent before it's marked likely sold. Use 2 to avoid false positives from search-ranking shuffle.",
                        "default": 2
                    },
                    "emitActiveItems": {
                        "title": "📤 Output still-active items too",
                        "type": "boolean",
                        "description": "In sell-through mode, also output items that are still listed (with days-listed and any price drop). Disable to output only newly-sold items and the summary (cheaper).",
                        "default": true
                    },
                    "minSellThroughAlertPct": {
                        "title": "🔔 Minimum sell-through % to alert",
                        "type": "integer",
                        "description": "In sell-through mode, only send a webhook alert when the sell-through rate is at least this percentage. Leave empty to always alert. Pairs with the Telegram/Discord/Slack fields below."
                    },
                    "includeArbitrageSummary": {
                        "title": "📊 Output arbitrage summary",
                        "type": "boolean",
                        "description": "Add one summary row comparing median/min/max prices across markets and naming the buy-low / sell-high pair.",
                        "default": true
                    },
                    "telegramBotToken": {
                        "title": "📨 Telegram bot token",
                        "type": "string",
                        "description": "Optional. Send each run's arbitrage alert to Telegram. Create a bot with @BotFather and paste its token here. Also fill in the chat ID below."
                    },
                    "telegramChatId": {
                        "title": "📨 Telegram chat ID",
                        "type": "string",
                        "description": "Optional. The chat or channel ID to send Telegram alerts to (e.g. your user ID, or -100... for a channel). Required if a bot token is set."
                    },
                    "discordWebhookUrl": {
                        "title": "📨 Discord webhook URL",
                        "type": "string",
                        "description": "Optional. Send each run's arbitrage alert to a Discord channel. Paste an Incoming Webhook URL (Server Settings → Integrations → Webhooks)."
                    },
                    "slackWebhookUrl": {
                        "title": "📨 Slack webhook URL",
                        "type": "string",
                        "description": "Optional. Send each run's arbitrage alert to a Slack channel. Paste an Incoming Webhook URL (api.slack.com/messaging/webhooks)."
                    },
                    "minSpreadPctAlert": {
                        "title": "🔔 Minimum spread % to alert",
                        "type": "integer",
                        "description": "Only send alerts when the cross-country median spread is at least this percentage. Leave empty to always alert. Useful for scheduled runs that should only ping you on real opportunities."
                    },
                    "alertTopListings": {
                        "title": "🔔 Listings per alert",
                        "minimum": 1,
                        "type": "integer",
                        "description": "How many of the cheapest listings to include in each alert message.",
                        "default": 5
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
