Vinotify Logovinotify
Login

Developer docs

Connect Vinotify to a poller, bot, coding agent, or compatible MCP client. The integration surface reads the same Vinted alerts as the dashboard and does not require a Vinted login.

Integrations require the Pro plan. See pricing for plan details. This page is currently English-only; localized documentation is a follow-up.

Authentication

Sign in, open Integrations, and create a token with a name. Write access is off by default. A token is account-scoped: it covers the searches your account owns now and searches you create later.

The token value is returned only in the create response. Vinotify stores a one-way digest, so the full value is not returned by the token list route. Treat it like a password: keep it in a local environment variable or secret store, never in a URL, chat, log, or committed file.

Authorization: Bearer YOUR_TOKEN

Read access is available with every integration token. A token created with write access has can_write: true; the MCP write tools also require the server-side write feature to be enabled. Revoking a token from Integrations, or with either revoke route below, makes it unusable.

POST /api/v1/integrations/tokens/{token_id}/revoke
DELETE /api/v1/integrations/tokens/{token_id}/revoke

MCP

The hosted MCP endpoint is a stateless JSON-RPC endpoint. Send POST requests with JSON and the bearer header; it returns application/json. It supports MCP protocol versions 2025-06-18, 2025-03-26, and 2024-11-05.

{
  "mcpServers": {
    "vinotify": {
      "url": "https://vinotify.me/api/v1/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_TOKEN"
      }
    }
  }
}

For a client that uses the standard JSON-RPC flow, call initialize, then tools/list, and use tools/call for a tool. Notifications are accepted without a response body.

MCP read tools and parameters
ToolParameters
list_searchesNo arguments. Returns active searches with id, name, market, active, last_checked, pre_alerts, pre_eligible, pre_ineligible_reason, and an account_fingerprint. pre_alerts_available says if your account can use Pre.
get_new_itemssearch_id (required integer); cursor (string, default 0-0, max 64 characters); wait (integer 0–30, default 0); limit (integer 1–100, default 25).
whats_newcursors (object of string cursors); since_minutes (integer 1–2880, default 60); limit_per_search (integer 1–25, default 10); wait (integer 0–30, default 0).

Write tools are exposed only for a write-scoped token while the server write flag is enabled:

MCP write tools and parameters
ToolParameters
create_searchname is required; search_text can be empty when a narrowing filter such as catalog_ids or brand_ids is set. Optional: market (default uk), price_from, price_to, brand_filter, size_filter, excluded_keywords, included_keywords, blocked_sellers, condition_filter, catalog_ids (up to 500), brand_ids (up to 20), size_ids (up to 50), category_node_id, notifications (default or none), pre_alerts (Pre early alerts, Pro accounts with Pre access only). price_from cannot be higher than price_to.
update_searchsearch_id is required. Optional: name, search_text, price_from, price_to, brand_filter, size_filter, excluded_keywords, included_keywords, blocked_sellers, condition_filter, catalog_ids, brand_ids, size_ids, category_node_id, notifications, pre_alerts.
pause_searchsearch_id (required positive integer).
resume_searchsearch_id (required positive integer).
delete_searchsearch_id (required positive integer). Removes the search from your plan at once. Its found items stay for 7 days, like all found items. Deleting it again is a no-op.

create_search.market accepts these verified market codes: uk, ie, fr, de, es, it, nl, be, at, lu, pt, us, au, pl, cz, se, dk, fi, gr, hr, hu, ro, si, sk, ee, lv, lt. Its filter field bounds are: name up to 100 characters; search_text up to 200; price fields from 0 to 10000; brand up to 1000; size and blocked_sellers up to 500; excluded and included keywords up to 1000; condition_filter up to 10 strings.

REST

Dashboard token-management routes use the authenticated dashboard user. Discovery and event routes use the bearer header shown above.

Vinotify integration REST endpoints
Method and pathAuth and purpose
POST /api/v1/integrations/tokensDashboard session. Body: name and optional allow_writes.
GET /api/v1/integrations/tokensDashboard session. Lists token metadata; not the raw token.
GET /api/v1/integrations/activityDashboard session. Returns recent assistant write audit entries.
POST or DELETE /api/v1/integrations/tokens/{token_id}/revokeDashboard session. Revokes a token.
GET /api/v1/integrations/searchesBearer token. Legacy all-owned search discovery.
GET /api/v1/integrations/discovery/v2Bearer token. Active search discovery with account_fingerprint. Add include_paused=true to list paused searches too (each entry then carries active), and details=true for market, markets, notifications, filters, created_at, and last_checked per search.
GET /api/v1/integrations/searches/{search_id}Bearer token. One search's definition: id, name, active, market, markets, notifications, filters, created_at, last_checked.
GET /api/v1/integrations/eventsBearer token. Event feed; use search_id, cursor, limit, and wait or wait_seconds.
GET or POST /api/v1/integrations/events/batchBearer token. One feed for many searches. GET takes search_ids (comma list), cursors (id:cursor pairs, comma list), cursor, limit, and wait; POST takes the same as JSON with cursors as an object. Without search_ids it reads every active search.
GET /api/v1/integrations/searches/{search_id}/eventsBearer token. Path-form event feed for one search.
GET /api/v1/integrations/searches/{search_id}/webhook/eventsBearer token. Webhook-named alias of the path-form event feed.

For event routes, cursor defaults to 0-0 and is limited to 64 characters; limit defaults to 50 and is capped at 100; wait and wait_seconds are bounded to 30 seconds. A cursor of $ (or latest) starts from now: the response returns no history and a concrete next_cursor to store, so never store $ itself.

GET https://vinotify.me/api/v1/integrations/events?search_id=42&cursor=0-0&wait=30
Authorization: Bearer YOUR_TOKEN
{
  "schema_version": 2,
  "search_id": 42,
  "events": [
    {
      "schema_version": 2,
      "event_id": "evt_…",
      "detected_at": "2026-09-08T12:00:00+00:00",
      "search_id": 42,
      "item_id": "123456789",
      "search_name": "Nike trainers",
      "market": "uk",
      "currency": "GBP",
      "items": [{
        "id": "123456789",
        "item_id": "123456789",
        "price": 55,
        "currency": "GBP",
        "title": "Nike trainers",
        "url": "https://www.vinted.co.uk/items/123456789",
        "listed_at": "2026-09-08T11:59:10+00:00"
      }],
      "cursor": "1725796800000-0"
    }
  ],
  "cursor": "0-0",
  "next_cursor": "1725796800000-0",
  "has_more": false
}

The batch feed reads several searches in one long poll and uses one long-poll slot. Each event carries its search_id and keeps the single-feed shape. Cursors are per search: send them as cursors (searches you omit use cursor, default 0-0) and store next_cursors. A cursor that fell out of retention does not fail the request; it is reported under cursor_expired for that search only, with reset_cursor: 0-0. Naming a search the token does not own returns 403; more searches than your plan's limit returns 400 when named or 409 when defaulted.

POST https://vinotify.me/api/v1/integrations/events/batch
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json

{"search_ids": [42, 57], "cursors": {"42": "1725796800000-0"}, "cursor": "$", "wait": 30}
{
  "schema_version": 2,
  "search_ids": [42, 57],
  "events": [
    { "event_id": "evt_…", "search_id": 42, "item_id": "123456789", "cursor": "1725796801000-0", "items": [{ "…": "…" }] },
    { "event_id": "evt_…", "search_id": 57, "item_id": "987654321", "cursor": "1725796802000-0", "items": [{ "…": "…" }] }
  ],
  "cursors": { "42": "1725796800000-0", "57": "1725796799000-0" },
  "next_cursors": { "42": "1725796801000-0", "57": "1725796802000-0" },
  "cursor_expired": {},
  "has_more": false
}

Search writes

These routes are the REST form of the MCP write tools. They need a write-scoped bearer token and are available only while the server REST write flag is enabled. The same input creates the same search on either surface, and both surfaces share one write budget per token.

Vinotify integration REST write endpoints
Method and pathPurpose
POST /api/v1/integrations/searchesCreate a search. JSON body with the create_search fields. Returns 201 with search and plan.
PATCH /api/v1/integrations/searches/{search_id}Change a search's name, filters, or notifications setting. JSON body with the update_search fields; only the fields you send change.
POST /api/v1/integrations/searches/{search_id}/pausePause a search. No body.
POST /api/v1/integrations/searches/{search_id}/resumeResume a search. No body. Your plan's search limit applies.
DELETE /api/v1/integrations/searches/{search_id}Delete a search. No body. Repeating it is a no-op.
POST https://vinotify.me/api/v1/integrations/searches
Authorization: Bearer YOUR_TOKEN
Content-Type: application/json

{"name": "Wool coats", "search_text": "wool coat", "market": "uk", "price_to": 80}

A write error returns a JSON body with error and message: 400 invalid_request; 403 write_tools_disabled or write_not_allowed for a read-only token; 404 not_found for a search you do not own; 429 rate_limited with retry_after and a Retry-After header; 503 unavailable.

Webhooks

Vinotify delivers new items two ways. Push posts each batch to a URL you own as soon as it is found. Pull lets your consumer read an event feed on its own schedule. Push is the lower-latency option; pull is the one that can catch up after downtime. Both require the Pro plan.

Push: outbound POST

Each Pro search has its own webhook secret. Read it, and set the destination that receives deliveries, with these routes. Both authenticate with your dashboard session rather than a bearer token, because they configure the search itself.

Vinotify webhook configuration routes
Method and pathPurpose
GET /api/v1/searches/{search_id}/webhookReturns the search's webhook_secret, its poll_url, and the currently configured external_url.
PUT /api/v1/searches/{search_id}/webhook/external-urlSets or clears the destination that receives POSTs. Body: url. Send an empty string to stop delivery.
GET /api/v1/searches/{search_id}/webhook/latest?secret=…Returns the most recent payload for this search, authenticated by the secret rather than a session. Cached for 24 hours.

The destination must be a public HTTPS endpoint. Vinotify validates it when you save it and again immediately before each delivery, and rejects addresses that resolve to private or internal networks.

Vinotify posts this body when a search finds new items:

POST https://your-endpoint.example.com/vinotify
Content-Type: application/json

{
  "event": "new_items",
  "search_id": 42,
  "search_name": "Carhartt jackets",
  "item_count": 2,
  "items": [ /* matching listings */ ]
}

Push delivery is best effort and is not retried. Respond quickly and queue the work on your side. If you need a guarantee that nothing is missed, run the pull feed below alongside it, or fall back to the /webhook/latest route above.

Pull: the event feed

The bearer-authenticated event feed is the durable option. Poll https://vinotify.me/api/v1/integrations/events, or the per-search route /api/v1/integrations/searches/{search_id}/events, with wait=30 to hold the connection open until something arrives. To follow many searches with one connection, poll https://vinotify.me/api/v1/integrations/events/batch instead; it returns per-search cursors and holds one long-poll slot.

A search created or updated with notifications: "none" is feed-only: Vinotify still records its matches, publishes them to the event feed, and posts them to a push webhook, but sends no email or phone push for it. Its matches still appear in the app's Notifications list. The default, notifications: "default", keeps the search's normal delivery. Editing the search in the dashboard keeps the setting.

Events are delivered at least once, so a retry can repeat an event_id. Deduplicate on that value and persist next_cursor after every response. Streams keep 48 hours of history and 10,000 entries by default; a cursor older than the retained window, or older than the oldest entry of a full stream, returns 410 cursor_expired with reset_cursor: 0-0.

The event envelope contains schema_version, event_id, detected_at, search_id, item_id, market, currency, and an items array. Item fields can include id, item_id, price, currency, title, brand, size, condition, condition_code, url, and photo when present. detected_at is when we found the item. listed_at is when it was listed on Vinted: Vinted's own time when it gives one, otherwise our estimate from the item ID. listed_at is left out when we cannot tell.

Pre (early alerts). Set pre_alerts: true on a search to get its alerts early. Pre is for Pro accounts with Pre access; for any other account, true is refused with 403 and error pre_not_available, and false always works. Pre can use search text, brand, price and size. It cannot read a category or a seller country, so a search with one of those still saves, keeps its filters, and gets normal alerts. Every search definition shows pre_alerts, pre_eligible and pre_ineligible_reason (for example unseen_filter:seller_countries). A Pre item has pre_alert: true in the feed, in long-poll events and in webhook payloads; normal items leave it out. pre_alerts_available in discovery/v2?details=true and in list_searches says if your account can use Pre.

Limits and errors

  • Default request budget: 240 requests per minute per token.
  • Default concurrent long-poll budget: 12 per token.
  • Write budget: 50 attempted writes per minute and 500 per day per token, shared by REST and MCP. The daily budget resets at 00:00 UTC.
  • MCP discovery and list_searches cap active searches at your plan's search limit (50 for Pro); whats_new caps the combined response at 200 events; the batch feed reads at most that many searches per request and returns at most limit events (100) across them.
  • ID filters: catalog_ids up to 500, brand_ids up to 20, size_ids up to 50, all non-negative integers; material_ids and color_ids are not accepted because the crawler does not apply them.
  • These budgets are configurable server-side. The values above are the current production values.
REST and MCP integration errors
SurfaceVerified errors and recovery
REST401 invalid or revoked token; 403 plan, ownership, write-flag, or read-only token failure; 400 invalid request or cursor; 404 missing search or token; 409 discovery over your plan's search limit; 410 cursor_expired with reset_cursor: 0-0; 422 token validation; 429 rate_limited with Retry-After; 503 feed unavailable.
JSON-RPC-32700 parse error; -32600 invalid request or unsupported batch; -32601 method not found; -32602 invalid params; -32603 internal error.
MCP toolsTool results can report bad_request, invalid_request, not_found, cursor_expired, pre_not_available, rate_limited, unavailable, write_not_allowed, write_tools_disabled, too_many_searches, or internal.