# Second-hand Deal Scanner ES — Vinted & Milanuncios vs eBay Sold (`jdepablos/second-hand-deal-scanner-es`) Actor

Finds underpriced live listings on Vinted & Milanuncios by cross-checking real eBay SOLD prices: deals ranked by estimated resale profit, with valuation stats attached. Built for resellers and AI agents.

- **URL**: https://apify.com/jdepablos/second-hand-deal-scanner-es.md
- **Developed by:** [Juan de Pablos](https://apify.com/jdepablos) (community)
- **Categories:** E-commerce, Automation
- **Stats:** 2 total users, 1 monthly users, 86.4% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $40.00 / 1,000 watched item scans

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — 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

## Second-hand Deal Scanner EU — Vinted, Wallapop & Milanuncios vs Real eBay Sold Prices

**One call = one item watched.** Give it any item ("Game Boy Micro") and a country (Spain, France, Germany, Italy or the UK): it scans live Vinted listings (plus Wallapop & Milanuncios in Spain), values the item from confirmed eBay **sold** prices on the local eBay site, and returns only the listings you can actually profit from — ranked by estimated net profit.

Most marketplace scrapers dump every listing on you. This Actor answers the question resellers actually have: **"Which of these is a real deal, and how much would I make?"**

### What you get per item

```json
{
  "query": "Game Boy Micro",
  "valuation": { "marketplace": "ebay.es", "median": 218.69, "n": 183, "confidence": "high", "currency": "EUR" },
  "deals": [
    {
      "source": "vinted", "title": "Game Boy micro en perfecto estado",
      "price": 100, "url": "https://www.vinted.es/items/...",
      "economics": {
        "estBuyTotal": 108.7, "estResaleNet": 162.92, "resaleShipping": 27.34,
        "estProfit": 54.22, "estMarginPct": 49.65, "verdict": "deal"
      }
    }
  ],
  "meta": { "listingsScanned": 67, "candidatesAfterFilters": 13,
    "filteredOut": { "titleMismatch": 21, "accessory": 3, "junk": 2, "suspiciouslyCheap": 5 } }
}
```

Real example above: 40 live listings scanned, 3 genuine deals found — a working console at €100 versus a €218.69 median of 183 confirmed sales.

### Why the deals are trustworthy

- **Valued against SOLD prices, not asking prices** — the resale value comes from confirmed eBay sales (median of up to 240 recent comps, cleaned of lots/for-parts/repro junk).
- **False-positive killers built in**: listings for a *different* product in the same family ("FIFA 2006 for GBA" when you watch a Game Boy Micro), accessories ("stand for...", "case for..."), and too-cheap-to-be-true mismatches (below 10% of median) are filtered out — each rejection is counted in `meta.filteredOut` so you can audit it.
- **Honest economics**: buy side includes Vinted buyer protection (~5% + €0.70) and shipping; sell side deducts marketplace fees (~13%) and real median shipping from the comps. All rates are overridable.
- **Per-source resilience**: if one source blocks or changes, you still get deals from the others, with the failure documented in `meta.sourceErrors`.

### Use cases

- **Resellers / flippers**: watch your 20 best-known items, run daily, buy only what clears your margin threshold.
- **AI agents**: one tool call = ranked arbitrage opportunities with the math already done.
- **Collectors**: get alerted when your grail shows up underpriced on Spanish second-hand markets.

### Input

| Field | Description |
|---|---|
| `query` | Item to watch, e.g. `"Game Boy Micro"` — use a canonical product name |
| `country` | `ES` (default), `FR`, `DE`, `IT`, `UK` — sets Vinted domain, eBay site and proxy country |
| `items` | Watchlist mode: up to 20 items per run with per-item overrides |
| `sources` | `vinted`, `milanuncios`, `wallapop` (all by default) |
| `marketplaceForComps` | eBay site for valuation (default `ebay.es`) |
| `marginMinPct` | Minimum estimated profit margin to report a deal (default 25) |
| `priceMax` | Ignore live listings above this price |
| `minTitleMatch` | Title relevance threshold 0-1 (default 0.75) |
| `priceSanityMinPct` | Listings below this % of median = different product (default 10) |
| `economics` | Override fee/shipping assumptions |

### Use with AI agents (MCP)

This Actor is exposed as a tool on the [Apify MCP Server](https://mcp.apify.com):

```json
{
  "mcpServers": {
    "deal-scanner-es": {
      "url": "https://mcp.apify.com?tools=jdepablos/second-hand-deal-scanner-es",
      "headers": { "Authorization": "Bearer <APIFY_TOKEN>" }
    }
  }
}
```

Pairs well with [eBay Sold Price Appraiser](https://apify.com/jdepablos/ebay-sold-price-appraiser) — same valuation engine, standalone appraisals.

### Pricing

Pay per event: **one flat fee per watched item scanned** — all sources, valuation and deal math included. Failed items are never charged.

### FAQ

**Why did my scan return 0 deals?** That's the product working: most live listings are fairly priced. Lower `marginMinPct` to see borderline candidates, and check `meta.filteredOut` to see what was rejected and why.

**Are the profit numbers guaranteed?** They're estimates: median resale minus realistic fees and shipping. Condition, completeness (box/charger) and negotiation move the final number. The comps and their URLs are in the valuation so you can verify before buying.

**Does it work outside Spain?** Yes — set `country` to FR, DE, IT or UK to scan the local Vinted against the local eBay sold prices. Wallapop and Milanuncios are Spain-only extras. Cross-country arbitrage (buy FR, sell DE) works by combining `country` with an explicit `marketplaceForComps`.

### More data tools by this developer

- [eBay Sold Price Appraiser — real market value from confirmed sales](https://apify.com/jdepablos/ebay-sold-price-appraiser)
- [Spanish Company Feed (BORME) — daily registry acts as JSON](https://apify.com/jdepablos/borme-company-feed)
- [Spain Public Auctions (BOE) — judicial auctions with market comparison](https://apify.com/jdepablos/spain-boe-auctions)
- [Trademark Watch (TMview) — new filings & opposition deadlines](https://apify.com/jdepablos/trademark-watch-tmview)

# Actor input Schema

## `query` (type: `string`):

Item you want deals for, e.g. 'Game Boy Micro'. Use a canonical product name — it drives both the source search and the eBay valuation. For multiple items use 'items'.

## `items` (type: `array`):

Up to 20 items per run. Each entry: {"query": "..."} plus any per-item overrides (priceMax, marginMinPct, sources, ...).

## `country` (type: `string`):

Market to scan. Determines the Vinted domain, the default eBay site for valuation and the proxy country. Wallapop & Milanuncios are Spain-only, Subito is Italy-only; unsupported sources are skipped.

## `sources` (type: `array`):

Marketplaces to scan for live listings. Wallapop & Milanuncios are Spain-only, Subito is Italy-only; unsupported sources are skipped per country.

## `marketplaceForComps` (type: `string`):

Where resale value is computed from sold listings. Defaults to ebay.com — the most liquid and reliable market for valuation. Pick a local eBay site to keep currencies consistent with the source country.

## `marginMinPct` (type: `integer`):

Only report listings whose estimated profit margin (vs estimated buy total) reaches this percentage.

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

Ignore live listings above this price (EUR).

## `condition` (type: `string`):

Restrict the eBay sold comps used for valuation.

## `minTitleMatch` (type: `string`):

0-1: fraction of query words that must appear in a listing title (source search relevance is loose — this kills false positives). Default 0.75.

## `priceSanityMinPct` (type: `integer`):

Listings priced below this % of the resale median are treated as a different product (accessory, single game, empty box), not a deal. Default 10.

## `maxListingsPerSource` (type: `integer`):

How many live listings to pull from each source per item.

## `strictClean` (type: `boolean`):

Drop lots/bundles/for-parts/repro listings on both sides (valuation comps AND live candidates). Recommended.

## `economics` (type: `object`):

Optional cost model overrides: {"resaleFeePct": 13, "vintedBuyerFeePct": 5, "vintedShippingEst": 3.5, "milanunciosShippingEst": 0, "wallapopBuyerFeePct": 5, "wallapopShippingEst": 4}.

## `proxy` (type: `object`):

Sources use DataDome — residential ES proxy is strongly recommended (default).

## `monitorMode` (type: `boolean`):

For scheduled smoke tests: when the source blocks every attempt (anti-bot weather, not a code fault), the run exits SUCCEEDED with a clear status message instead of FAILED, and notifies monitorEmail. Code faults (unrecognized markup) still fail the run.

## `monitorEmail` (type: `string`):

Email to notify (via apify/send-mail) when monitor mode detects a fully blocked source. On Apify free plans this must be the account owner email.

## Actor input object example

```json
{
  "query": "Game Boy Micro",
  "country": "ES",
  "marketplaceForComps": "ebay.com",
  "marginMinPct": 25,
  "condition": "any",
  "minTitleMatch": "0.75",
  "priceSanityMinPct": 10,
  "maxListingsPerSource": 40,
  "strictClean": true,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "ES"
  },
  "monitorMode": false
}
```

# 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 = {
    "query": "Game Boy Micro",
    "marketplaceForComps": "ebay.com",
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "ES"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("jdepablos/second-hand-deal-scanner-es").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 = {
    "query": "Game Boy Micro",
    "marketplaceForComps": "ebay.com",
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "ES",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("jdepablos/second-hand-deal-scanner-es").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 '{
  "query": "Game Boy Micro",
  "marketplaceForComps": "ebay.com",
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "ES"
  }
}' |
apify call jdepablos/second-hand-deal-scanner-es --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=jdepablos/second-hand-deal-scanner-es",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/YCQbgWeS3TFHglFc1/builds/WWPLii3yCv9BzF7pW/openapi.json
