# Vinted Products Deal Detector (`alkausari_mujahid/vinted-products-deal-detector`) Actor

Get instant alerts when underpriced items appear on Vinted. Pick your product, price range, and condition — it learns the real market price and pings you the moment a genuine bargain shows up, with your savings on every alert.

- **URL**: https://apify.com/alkausari\_mujahid/vinted-products-deal-detector.md
- **Developed by:** [Alkausari M](https://apify.com/alkausari_mujahid) (community)
- **Categories:** E-commerce, Automation, Integrations
- **Stats:** 5 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.00 / 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.

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

**Get an instant alert the moment an underpriced item appears on [Vinted](https://www.vinted.com).** You pick the product, your price range, and the condition you want — the Actor learns the real market price, watches the newest listings around the clock, and pings you only when something is a genuine bargain. Every alert tells you the **typical market price** and **how much you'd save**, so you can act in seconds.

> Built and maintained by **Alkausari M**.

---

### ✦ Highlights

- 🔔  **Instant deal alerts** — delivered straight to Slack, Discord, Telegram, Make, Zapier, or your own app
- 📉  **Real market-price intelligence** — knows the going rate for each condition from hundreds of live listings, not guesswork
- 💸  **Savings shown on every alert** — see exactly how far below the typical price each deal is, in $ and %
- 🎯  **You set the filters** — product, price range, and the exact conditions you'll accept
- 🧠  **No spam, no duplicates** — you never get the same listing twice, and only real bargains come through
- ⏱  **Set it and forget it** — schedule one product per run and let it watch around the clock
- 📊  **Export anywhere** — JSON, CSV, Excel, or live via the Apify API
- 🛡  **Anti-blocking built-in** — residential proxy support and smart retries

---

### ⚙ How it works

1. **Name your product.** Just type what you're after — e.g. *"Dior Sauvage"* or *"iPhone 15"*. The Actor builds the Vinted search for you automatically.
2. **Set your filters.** Add a price range and the conditions you'll accept, and where you want alerts sent.
3. **Let it run.** The Actor figures out the normal market price, keeps an eye on new listings, and alerts you instantly whenever a deal beats the market by a meaningful margin (set automatically by the item's value).

```jsonc
// Example input — one product per run
{
    "product": "Dior Sauvage",
    "webhookUrl": "https://webhook.site/your-unique-url",
    "minPrice": 30,
    "maxPrice": 90,
    "conditions": ["Good", "Average"],
    "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
}
````

> \[!TIP]
> Use the product name the way buyers search for it — a clear brand + model (*"Nike Air Force 1"*, *"Dior Sauvage 100ml"*) gives the most relevant matches. Your price range and conditions are applied automatically; you don't need to set up anything on Vinted itself.

For best results, **schedule the Actor to run every 10–30 minutes** in your Apify Console. The best deals sell within minutes, so the more often it checks, the more you catch.

**Powered by the Vinted Products Crawler.** To read listings from Vinted, this Actor automatically uses its companion extractor, the **[Vinted Products Crawler](https://apify.com/alkausari_mujahid/vinted-products-crawler)**. You don't need to install or set up anything — the first time the Deal Detector runs, the crawler is added to your Apify account automatically and called behind the scenes.

> \[!IMPORTANT]
> **Billing:** the Vinted Products Crawler runs as a **separate Actor** in your Apify Console, so each job appears as its own run with its own cost. This is expected — the Deal Detector orchestrates the crawler and layers the market-price and deal-detection logic on top.

***

### 💰 Market price & savings — on every deal

This is what makes the alerts worth acting on. For each product and each condition, the Actor builds a **market median price** from hundreds of recent listings — the honest "going rate." Every new listing is measured against it:

```
Market price (Very good condition):  $120   ← what this normally sells for
This listing:                        $80
                                     ─────
You save:                            $40     ( 33% below market )   ✅  DEAL
```

The discount needed to count as a deal is set **automatically from each item's market value** — cheaper items need a bigger discount to be worth flagging (a 20% saving on a $10 item is only $2), while higher-value items qualify at a smaller percentage. Everyday pricing is ignored, so your alerts stay meaningful instead of constant. Every alert carries:

| Metric | What it tells you |
|---|---|
| **Estimated market price** | The typical price this item sells for in its condition |
| **Estimated savings** | How much cheaper this listing is than the market price, in $ |
| **Estimated profit** | Your savings *after* resale costs — market price − listing price − (resale fee % × market price). The resale fee defaults to 10% and is adjustable in the input |
| **% below market** | The discount as a percentage |
| **Based on** | How many listings the market price was calculated from |

> \[!NOTE]
> For a brand-new or very specific search, the Actor needs to see enough listings before it can trust a market price. Until then, those items are recorded but **no alert is sent** — this prevents false bargains based on too little data.

***

### 🔎 How your filters shape the results

The Actor does two things, and your filters apply to both:

- **Building the market price** (runs occasionally in the background): it scrapes many listings of your product **within your price range and condition** to work out the typical price. Your **price range matters here** — it keeps unrelated cheap items out of the calculation (e.g. phone cases and cables when you search *"iPhone 15"*), so the market price reflects the actual product, not accessories.
- **Watching for deals** (every run): it scans the newest listings in the same price range and condition and compares each one to that market price.

**About "Sort by":**

- **Newest first** (recommended) and **Relevance** are applied to **both** — so the market price is based on current, representative listings.
- **Price: low to high / high to low** are applied to the **live deal scan only**. Using them to build the market price would distort it (it would look at just the cheapest or most expensive items), so the Actor automatically skips them there.

***

### 📦 What you get back

Every alert is also saved as a structured record you can download or pipe anywhere:

Each evaluated item is saved as one record. **The webhook delivers the exact same record** — what you download mirrors what your alert receives:

```json
{
    "alertName": "Dior Sauvage",
    "itemId": "8700440386",
    "title": "Dior Sauvage EDT 100ml — barely used",
    "url": "https://www.vinted.com/items/8700440386-dior-sauvage",
    "condition": "Very good",
    "brand": "Dior",
    "adPrice": 45,                 // the listing's asking price
    "marketPrice": 70,             // typical market price for this condition
    "estimatedSaving": 25,         // marketPrice − adPrice
    "estimatedProfit": 18,         // saving after resale costs
    "pctBelowMarket": 35.7,
    "discountThreshold": 25,       // the % it needed to beat (auto, by value)
    "marketSampleSize": 96,        // listings the market price was based on
    "isDeal": true,
    "noBaseline": false,
    "seller": "...", "sellerLocation": "...", "uploaded": "an hour ago",
    "freeShipping": true, "images": ["..."], "description": "...",
    "scrapedAt": "2026-06-05T14:32:11.000Z"
}
```

When a deal is found, the webhook wraps that same record:

```jsonc
{
    "event": "deal_detected",
    "deal": { /* exactly the record above */ }
}
```

> \[!NOTE]
> The **dataset** stores *every* evaluated item (so you can review near-misses too), each with `isDeal`. The **webhook** fires only for items where `isDeal` is `true`. For non-deal or "no baseline" rows, the market fields (`marketPrice`, `estimatedSaving`, etc.) are `null`.

***

### 📋 Input

One product per run. To monitor several products, set up one scheduled task per product.

| Field | Description | Required | Default |
|---|---|---|---|
| **Product** (`product`) | The product name to search for (e.g. *"Dior Sauvage"*, *"iPhone 15"*) — the Actor builds the Vinted search automatically | Yes | — |
| **Webhook URL** (`webhookUrl`) | Where alerts are delivered (Slack, Discord, Make, Zapier, or your app) | Yes | — |
| **Price range** (`minPrice` / `maxPrice`) | Only alert on items within this price band | No | no limit |
| **Condition** (`conditions`) | How picky to be, as simple tiers (each covers several Vinted conditions so more listings match): **Good** (New with tags, New without tags, Very good), **Average** (Good), **Poor** (Satisfactory, Not fully functional) | No | Good + Average |
| **Sort by** (`order`) | How listings are scanned: *Newest first* (recommended), *Relevance*, *Price: low to high*, *Price: high to low*. Newest first and Relevance also shape the market-price baseline; the price sorts apply to the live scan only (they'd distort the median). See *How your filters shape the results* | No | Newest first |
| **Advanced: Vinted URL** (`vintedUrl`) | Power users: paste a fully-filtered Vinted search URL (any category, brand, size, colour, price, etc.). When set, it defines the search and the Product/Conditions fields are ignored. Include price in the URL; the Actor only strips sort/page and applies your chosen Sort | No | — |
| **Resale fee** (`resaleFeePct`) | Assumed resale cost (fees + shipping) as a % of market price, used for the profit estimate | No | `10%` |
| **Proxy Configuration** | Leave as default if unsure; residential proxies improve reliability | No | Residential |

> \[!NOTE]
> **Advanced settings** (how many pages to scan, how often to refresh the market price, how long to remember seen items) have sensible defaults — you can ignore them unless you want to fine-tune cost or freshness.

***

### 💡 Use cases

- **Reselling & flipping** — catch items priced below market, resell at the going rate.
- **Personal bargain hunting** — set your wishlist and get pinged the moment a deal drops.
- **A deal-alert service** — schedule one task per product and fan the alerts out to your subscribers.
- **Price research** — watch how the going rate for a category or brand moves over time.
- **Automations** — pipe deals into Slack, Sheets, Make, Zapier, or a custom app via the Apify API.

***

### ❓ FAQ

**How does it know the "market price"?**
For each product and condition, it gathers hundreds of recent Vinted listings and takes the median — the middle price. That's a robust, real-world estimate of what an item normally sells for, and it refreshes automatically.

**Will I get flooded with alerts?**
No. Two safeguards keep it quiet: an **automatic discount threshold** (scaled to each item's value) so only real bargains qualify, and **duplicate filtering** so you never see the same listing twice.

**What's a "webhook" and how do I receive alerts?**
A webhook is just a link that receives the alert. For testing, create a free one at [webhook.site](https://webhook.site) and paste it in. For real use, connect Slack, Discord, Telegram, Make, or Zapier — or your own app — to turn each deal into a notification.

**Why didn't the first run send any alerts?**
By design. The **first run for a new search seeds quietly** — it learns the market price and records the current deals to the dataset, but doesn't fire alerts for the entire existing backlog (which could be dozens at once). From the next run on, only genuinely new listings alert. If you *want* alerts on that first run (for testing or a one-time catch-up), enable **Alert on the first run**.

**I'm not getting any alerts — why?**
Usually one of three things: it's the first run (seeds silently — see above), the Actor is still learning the market price, or your price range/conditions are very narrow. Widen the filters to catch more.

**Why is there a "Vinted Products Crawler" in my account?**
That's the companion extractor this Actor uses to read listings from Vinted, the **[Vinted Products Crawler](https://apify.com/alkausari_mujahid/vinted-products-crawler)**. It's added to your Apify account automatically the first time the Deal Detector runs — you don't need to set it up. Each crawler run is billed separately in your Console.

**Can I filter by category, brand, or size?**
Yes — use the **Advanced: Vinted URL** field. Filter your search on vinted.com exactly how you want (pick the category, brand, size, colour, etc.), copy the URL from your browser, and paste it in. It replaces the simple product search, while your Sort and Price settings are still applied. Leave it empty if a product name is enough.

**Can I monitor more than one product?**
Each run watches one product. To track several, create one scheduled task per product — each with its own filters and webhook. This keeps every run fast and focused.

**How often should it run?**
Great deals sell fast. Schedule it every **10–30 minutes** for the best catch rate.

**Is it legal to use?**
The Actor only reads publicly visible listing data. Use it responsibly and in line with [Vinted's Terms of Service](https://www.vinted.com/terms_and_conditions).

***

### 📮 Support

Bugs, feature requests, or custom scraping work — open an issue on Apify or email **<alkausarimujahid@gmail.com>**.

***

<sub>Built by **Alkausari M**. This Actor is independent and not affiliated with, endorsed by, or sponsored by Vinted. Use scraped data responsibly and in accordance with the [Vinted Terms of Service](https://www.vinted.com/terms_and_conditions) and applicable law.</sub>

# Actor input Schema

## `product` (type: `string`):

The product to monitor on Vinted, e.g. "Dior Sauvage" or "iPhone 15". The Actor builds the Vinted search automatically.

## `webhookUrl` (type: `string`):

Where deal alerts are sent — Slack, Discord, Make, Zapier, or your own app. Use https://webhook.site for testing.

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

Only alert on items priced at or above this (USD). Filters the Vinted search directly. Leave empty for no lower limit.

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

Only alert on items priced at or below this (USD). Filters the Vinted search directly. Leave empty for no upper limit.

## `conditions` (type: `array`):

How picky to be about item condition. Each tier covers several real Vinted conditions, so you still get plenty of matching listings:
• Good — New with tags, New without tags, Very good
• Average — Good
• Poor — Satisfactory, Not fully functional
Default (Good + Average) gives the best mix of quality and volume. Leave empty to accept everything.

## `order` (type: `string`):

How listings are scanned. "Newest first" is recommended — it catches freshly-posted deals before they sell. Newest first and Relevance also apply to the market-price baseline; the price sorts apply only to the live scan (they would skew the baseline median, so they're not used there).

## `vintedUrl` (type: `string`):

Optional, for power users. Filter a search on vinted.com however you like — category, brand, size, colour, price, anything — then paste the URL here. When set, it defines the search and the Product/Conditions fields above are ignored. Include the price filter in the URL itself; the Actor only strips the sort and page parameters and applies your chosen Sort. Leave empty to use the simple Product search.

## `resaleFeePct` (type: `integer`):

Assumed cost of reselling (platform fees + shipping) as a percentage of the market price. Used to turn gross savings into an estimated net profit: profit = market price − listing price − (this % × market price).

## `alertOnFirstRun` (type: `boolean`):

By default, the very first run for a new search seeds quietly — it learns the market price and records the current deals but does NOT send alerts, so you aren't flooded with the whole existing backlog. New listings alert normally from the next run on. Turn this on to also send alerts for everything found on the first run (useful for testing or a one-time catch-up).

## `baselineMaxAgeHours` (type: `integer`):

Rebuild the market price baseline if it is older than this. Lower values keep the median fresher but increase scraping costs.

## `baselinePages` (type: `integer`):

Number of search result pages to scrape when building the price baseline. More pages = more price samples = more accurate median. Each page yields ~48 items.

## `monitorPages` (type: `integer`):

Number of newest-first pages to check per run for new listings. Keep low (1–3) when scheduling runs every few minutes.

## `minSampleSize` (type: `integer`):

Minimum listings required per condition to compute a valid market median. Conditions with fewer samples are skipped — items in that condition will not trigger alerts until enough data is collected.

## `seenIdTtlHours` (type: `integer`):

How long to remember a processed item before re-evaluating it if it reappears (e.g. a seller relists at a lower price).

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

Proxy settings passed to the Vinted crawler. Residential proxies improve success rates but require a paid Apify plan.

## Actor input object example

```json
{
  "product": "Dior Sauvage",
  "conditions": [
    "Good",
    "Average"
  ],
  "order": "newest_first",
  "resaleFeePct": 10,
  "alertOnFirstRun": false,
  "baselineMaxAgeHours": 6,
  "baselinePages": 15,
  "monitorPages": 2,
  "minSampleSize": 8,
  "seenIdTtlHours": 24,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# 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 = {
    "product": "Dior Sauvage"
};

// Run the Actor and wait for it to finish
const run = await client.actor("alkausari_mujahid/vinted-products-deal-detector").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 = { "product": "Dior Sauvage" }

# Run the Actor and wait for it to finish
run = client.actor("alkausari_mujahid/vinted-products-deal-detector").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 '{
  "product": "Dior Sauvage"
}' |
apify call alkausari_mujahid/vinted-products-deal-detector --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=alkausari_mujahid/vinted-products-deal-detector",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Vinted Products Deal Detector",
        "description": "Get instant alerts when underpriced items appear on Vinted. Pick your product, price range, and condition — it learns the real market price and pings you the moment a genuine bargain shows up, with your savings on every alert.",
        "version": "0.0",
        "x-build-id": "kolFNCGWrpF0tCvLi"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/alkausari_mujahid~vinted-products-deal-detector/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-alkausari_mujahid-vinted-products-deal-detector",
                "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/alkausari_mujahid~vinted-products-deal-detector/runs": {
            "post": {
                "operationId": "runs-sync-alkausari_mujahid-vinted-products-deal-detector",
                "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/alkausari_mujahid~vinted-products-deal-detector/run-sync": {
            "post": {
                "operationId": "run-sync-alkausari_mujahid-vinted-products-deal-detector",
                "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": [
                    "product",
                    "webhookUrl"
                ],
                "properties": {
                    "product": {
                        "title": "Product",
                        "type": "string",
                        "description": "The product to monitor on Vinted, e.g. \"Dior Sauvage\" or \"iPhone 15\". The Actor builds the Vinted search automatically."
                    },
                    "webhookUrl": {
                        "title": "Webhook URL",
                        "type": "string",
                        "description": "Where deal alerts are sent — Slack, Discord, Make, Zapier, or your own app. Use https://webhook.site for testing."
                    },
                    "minPrice": {
                        "title": "Minimum Price ($)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Only alert on items priced at or above this (USD). Filters the Vinted search directly. Leave empty for no lower limit."
                    },
                    "maxPrice": {
                        "title": "Maximum Price ($)",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Only alert on items priced at or below this (USD). Filters the Vinted search directly. Leave empty for no upper limit."
                    },
                    "conditions": {
                        "title": "Condition",
                        "type": "array",
                        "description": "How picky to be about item condition. Each tier covers several real Vinted conditions, so you still get plenty of matching listings:\n• Good — New with tags, New without tags, Very good\n• Average — Good\n• Poor — Satisfactory, Not fully functional\nDefault (Good + Average) gives the best mix of quality and volume. Leave empty to accept everything.",
                        "items": {
                            "type": "string",
                            "enum": [
                                "Good",
                                "Average",
                                "Poor"
                            ],
                            "enumTitles": [
                                "Good — New with tags, New without tags, Very good",
                                "Average — Good",
                                "Poor — Satisfactory, Not fully functional"
                            ]
                        },
                        "default": [
                            "Good",
                            "Average"
                        ]
                    },
                    "order": {
                        "title": "Sort by",
                        "enum": [
                            "newest_first",
                            "relevance",
                            "price_low_to_high",
                            "price_high_to_low"
                        ],
                        "type": "string",
                        "description": "How listings are scanned. \"Newest first\" is recommended — it catches freshly-posted deals before they sell. Newest first and Relevance also apply to the market-price baseline; the price sorts apply only to the live scan (they would skew the baseline median, so they're not used there).",
                        "default": "newest_first"
                    },
                    "vintedUrl": {
                        "title": "Advanced: Vinted URL",
                        "type": "string",
                        "description": "Optional, for power users. Filter a search on vinted.com however you like — category, brand, size, colour, price, anything — then paste the URL here. When set, it defines the search and the Product/Conditions fields above are ignored. Include the price filter in the URL itself; the Actor only strips the sort and page parameters and applies your chosen Sort. Leave empty to use the simple Product search."
                    },
                    "resaleFeePct": {
                        "title": "Resale Fee (%) — for profit estimate",
                        "minimum": 0,
                        "maximum": 50,
                        "type": "integer",
                        "description": "Assumed cost of reselling (platform fees + shipping) as a percentage of the market price. Used to turn gross savings into an estimated net profit: profit = market price − listing price − (this % × market price).",
                        "default": 10
                    },
                    "alertOnFirstRun": {
                        "title": "Alert on the first run",
                        "type": "boolean",
                        "description": "By default, the very first run for a new search seeds quietly — it learns the market price and records the current deals but does NOT send alerts, so you aren't flooded with the whole existing backlog. New listings alert normally from the next run on. Turn this on to also send alerts for everything found on the first run (useful for testing or a one-time catch-up).",
                        "default": false
                    },
                    "baselineMaxAgeHours": {
                        "title": "Baseline Max Age (hours)",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Rebuild the market price baseline if it is older than this. Lower values keep the median fresher but increase scraping costs.",
                        "default": 6
                    },
                    "baselinePages": {
                        "title": "Baseline Pages",
                        "minimum": 1,
                        "maximum": 50,
                        "type": "integer",
                        "description": "Number of search result pages to scrape when building the price baseline. More pages = more price samples = more accurate median. Each page yields ~48 items.",
                        "default": 15
                    },
                    "monitorPages": {
                        "title": "Monitor Pages (per run)",
                        "minimum": 1,
                        "maximum": 10,
                        "type": "integer",
                        "description": "Number of newest-first pages to check per run for new listings. Keep low (1–3) when scheduling runs every few minutes.",
                        "default": 2
                    },
                    "minSampleSize": {
                        "title": "Min Sample Size for Baseline",
                        "minimum": 3,
                        "type": "integer",
                        "description": "Minimum listings required per condition to compute a valid market median. Conditions with fewer samples are skipped — items in that condition will not trigger alerts until enough data is collected.",
                        "default": 8
                    },
                    "seenIdTtlHours": {
                        "title": "Seen ID TTL (hours)",
                        "minimum": 1,
                        "type": "integer",
                        "description": "How long to remember a processed item before re-evaluating it if it reappears (e.g. a seller relists at a lower price).",
                        "default": 24
                    },
                    "proxyConfiguration": {
                        "title": "Proxy Configuration",
                        "type": "object",
                        "description": "Proxy settings passed to the Vinted crawler. Residential proxies improve success rates but require a paid Apify plan.",
                        "default": {
                            "useApifyProxy": true,
                            "apifyProxyGroups": [
                                "RESIDENTIAL"
                            ]
                        }
                    }
                }
            },
            "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
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
