Vinted API: Search Second-Hand Items as JSON
One GET request to /v1/vinted/search returns Vinted listings as JSON: title, price, service fee, total price, photos and the seller's id. Add country to pick the market and order=price_low_to_high to sort. Each call costs 1 credit, and you can repeat the same query across 19 country codes to price-check an item across markets.
How do you get Vinted data as JSON?
Send a GET request to https://api.perceptlayer.com/v1/vinted/search with your key in the X-API-Key header. The response is JSON with named fields, not a page of HTML. A free account gets 1,000 credits a month after you verify an email address, and a search costs 1 credit, so you can run the call below straight away.
Get a free API key, then keep it in an environment variable. Keys start with sk_live_; the authentication docs cover the api_key query parameter for places where you can't set a header.
curl "https://api.perceptlayer.com/v1/vinted/search?query=nike+shoes&country=DE" \
-H "X-API-Key: $API_KEY"
That is a search for "nike shoes" on the German market. You can also run it from the playground on the Vinted API page without writing any code. The catalogue has 10 Vinted endpoints in all; this guide uses search, filters, countries and item details.
What does the Vinted search response contain?
The search response wraps the listings in data.items and puts paging details in data.pagination. Every item has an id, a title, a relative url, a price object, a service_fee, a total_item_price, photos, a favourite_count and a user object. The excerpt below is trimmed from a recorded call to the request above.
{
"success": true,
"data": {
"items": [
{
"favourite_count": 66,
"id": 10490818547,
"item_box": {
"accessibility_label": "Nikeshoe size 38.5, Marke: Nike, Zustand: Sehr gut, Größe: 38.5, 20.00 €, 21.70 €",
"second_line": "38.5 · Sehr gut"
},
"price": { "amount": "20.00", "currency_code": "EUR" },
"promoted": false,
"service_fee": { "amount": "1.70", "currency_code": "EUR" },
"title": "Nikeshoe size 38.5",
"total_item_price": { "amount": "21.70", "currency_code": "EUR" },
"url": "/items/10490818547-nikeshoe-size-385",
…
},
…
],
"pagination": {
"current_page": 1,
"per_page": 24,
"total_entries": 960,
"total_pages": 40
},
…
},
"message": "Items retrieved successfully",
…
}
Three details matter if you're comparing prices. Amounts are strings, so convert them before you do arithmetic. price is the seller's price, while total_item_price includes the service fee (20.00 plus 1.70 gives 21.70 in this record). And promoted marks sponsored placements: the second item in the same recorded response has promoted set to true, so filter on it if you want organic results only.
Which parameters does the Vinted search endpoint take?
The search endpoint has 14 optional parameters and no required ones. Free text goes in q or query, sorting in order, price bounds in price_from and price_to, and the market in country. The ID filters (brand_ids, catalog_ids, color_ids, size_ids, material_ids, status_ids) take strings, so check the search endpoint page before you rely on a format.
| Parameter | Type | Allowed values or limit |
|---|---|---|
q, query |
string | up to 500 characters |
page |
integer | none stated |
per_page |
integer | none stated |
order |
string | relevance, newest_first, price_low_to_high, price_high_to_low |
brand_ids |
string | up to 500 characters |
catalog_ids |
string | up to 500 characters |
color_ids |
string | up to 200 characters |
size_ids |
string | up to 200 characters |
material_ids |
string | up to 200 characters |
status_ids |
string | up to 100 characters |
price_from, price_to |
number | none stated |
country |
string | FR, DE, ES, IT, NL, BE, AT, PL, CZ, LT, LU, SK, HU, RO, PT, SE, DK, FI, US |
For a cheapest-first view of used trainers between two prices, combine them: ?query=nike+shoes&country=DE&price_from=10&price_to=30&order=price_low_to_high.
How do filters fit in front of search?
GET /v1/vinted/filters accepts the same 14 optional parameters as search and costs 1 credit, so you can send it the same query and country you plan to search with. The Vinted filters endpoint page documents it. Search takes ID parameters such as brand_ids and size_ids, but this article doesn't show where to get those values.
The filters response wasn't recorded for this article, so it doesn't say what comes back. Run it in the playground on the Vinted API page and read the real response before you build on it. If you repeat the same calls, the caching guide covers TTLs and the credits you save.
How do you get the details of one Vinted item?
Call GET /v1/vinted/item-details with the item_id from a search result's id field. The only required parameter is item_id; country and include_member_items (a boolean) are optional. It costs 1 credit, like every Vinted endpoint. Its response wasn't recorded for this article, so run it in the playground on the Vinted API page to see what it returns.
curl "https://api.perceptlayer.com/v1/vinted/item-details?item_id=10490818547&country=DE" \
-H "X-API-Key: $API_KEY"
Two sibling endpoints take the same item_id: Item Shipping for delivery options and Similar Items for comparable listings. Item details and similar items also accept GB, which search doesn't.
How do you price-check an item across countries?
Run the same search once per country code and compare the prices that come back. The Countries endpoint takes no parameters and costs 1 credit. The search endpoint accepts 19 country codes, so one sweep is 19 calls × 1 credit = 19 credits.
The script below loops over the codes, asks for the cheapest listings first and keeps the lowest total_item_price per country. It waits a second between calls to stay inside the free tier's 1 request a second. Run it with pip install requests and API_KEY set.
import os
import time
import requests
BASE = "https://api.perceptlayer.com/v1/vinted/search"
HEADERS = {"X-API-Key": os.environ["API_KEY"]}
COUNTRIES = ["FR", "DE", "ES", "IT", "NL", "BE", "AT", "PL", "CZ", "LT",
"LU", "SK", "HU", "RO", "PT", "SE", "DK", "FI", "US"]
def cheapest(query, country):
r = requests.get(
BASE,
headers=HEADERS,
params={"query": query, "country": country, "order": "price_low_to_high"},
timeout=30,
)
if r.status_code != 200:
print(country, "failed:", r.status_code, r.json()["error"]["code"])
return None
items = r.json()["data"]["items"]
if not items:
return None
best = min(items, key=lambda i: float(i["total_item_price"]["amount"]))
total = best["total_item_price"]
return float(total["amount"]), total["currency_code"], best["url"]
for country in COUNTRIES:
print(country, cheapest("nike air max", country))
time.sleep(1)
Read the currency before you compare anything. Each result carries its own currency_code, so check it and convert with a rate you trust before ranking countries. For shipping data on a specific listing, the Item Shipping endpoint returns it.
One sweep returns the cheapest listing on the first page of each market, which is a sample, not the whole market. To read deeper, walk page up to total_pages; the pagination guide shows a safe loop. If the same item appears in several results, deduplicating listings covers matching without shared IDs.
What does a Vinted API call cost?
Every Vinted endpoint costs 1 credit on a successful call, and a failed call costs nothing. Each response carries X-Credits-Used and X-Credits-Remaining, so you can track the balance as you go. Walking the 40 pages of the recorded "nike shoes" search in Germany would cost 40 calls × 1 credit = 40 credits.
| Job | Calls | Credits |
|---|---|---|
| One search | 1 | 1 |
| One 19-country sweep | 19 × 1 | 19 |
| Sweep plus item details for each country's top hit | 19 + 19 | 38 |
| Daily 19-country sweep for 30 days | 30 × 19 | 570 |
The daily sweep fits inside the 1,000 free credits a month. Larger volumes use prepaid packs that last 12 months, with no subscription; see pricing for what credits cost and the credits docs for how they are debited. For the rules on request rates, read rate limits.
What should you build next?
Start with one query you actually resell or buy. Run it in the playground on the Vinted API page, then paste the cURL call into a script and move to the 19-country loop above. If you already track listings elsewhere, the eBay search results guide uses the same pattern, and the Marketplaces APIs page lists the other marketplace sources in the catalogue.
If a call fails, the errors docs list every status and code. The data is collected from publicly available sources and returned as found at the time of the call.
APIs in this post
Frequently asked questions
Which Vinted endpoints are available?
The catalogue has 10 Vinted endpoints: categories, countries, filters, item details, item shipping, search, similar items, suggestions, user items and user profile. All are GET requests and cost 1 credit on success. Data is collected from publicly available sources and returned as found at the time of the call.
How much does one Vinted search cost?
One successful search costs 1 credit, and so does every other Vinted endpoint. Failed calls cost nothing and return X-Credits-Used: 0. The free tier gives 1,000 credits a month with no credit card, so you can run 1,000 searches before you buy a pack. The pricing page shows what credits cost.
Can I search Vinted in the UK with this API?
The search endpoint accepts 19 country codes, and GB isn't one of them. Item details, similar items and suggestions do accept GB, so you can look up a known UK listing by item_id or get suggestions for a query. For search, use one of the 19 supported codes listed in the parameter table above.
How do I page through all the results?
Pass page and read data.pagination, which holds current_page, per_page, total_entries and total_pages. In the recorded call, 960 entries spread over 40 pages of 24. Each page is a separate call at 1 credit, so 40 pages cost 40 credits. Stop when current_page reaches total_pages.
What happens if I hit the rate limit?
A request over your account's rate returns a 429 with a Retry-After header giving the seconds to wait (see the MDN page for Retry-After and RFC 6585, which defines the 429 status code). Free accounts get 1 request a second, counted per minute across all keys. The 429 isn't billed. See errors for the full list of codes.