Ovdix API and MCP
What is available
- REST API
https://backend.ovdix.com/api/v1— JSON over HTTPS: advert search with filters, an advert in full, the category tree, a seller's storefront. - MCP server
https://backend.ovdix.com/mcp— the same four operations as tools for Claude, Cursor and any client that speaks MCP over Streamable HTTP. - Without a key both read only public data that anyone sees on the website. With an API key
/api/v1also manages your own adverts, drafts, photos and chats (MCP with a key comes next).
REST API: quick start
Reading endpoints are GET: parameters go in the query string with the same names as in the reference; a list is a repeated parameter (queries=a&queries=b). The response language follows Accept-Language or the lang parameter: en, ru, sr, ro, bg, hu, uk, de.
# Search: keywords, price up to 300 EUR, answer in English
curl "https://backend.ovdix.com/api/v1/adverts?queries=gitara&price_max=300¤cy=EUR&lang=en"
# Category tree, two levels, in Serbian
curl "https://backend.ovdix.com/api/v1/categories?lang=sr"
# One advert and a seller's storefront (ids come from the search)
curl "https://backend.ovdix.com/api/v1/adverts/<advert_id>"
curl "https://backend.ovdix.com/api/v1/storefronts/<seller_id>"import requests
response = requests.get(
"https://backend.ovdix.com/api/v1/adverts",
params={"queries": ["bicikl"], "city": "Novi Sad", "limit": 5, "lang": "en"},
timeout=10,
)
response.raise_for_status()
for advert in response.json()["adverts"]:
print(advert["title"], advert.get("price"), advert["currency"], advert["url"])Search tips: pass 1–3 words of the item itself — every word must occur in the title or description. Most adverts are written in Serbian, so a second keyword set in Serbian (Latin) finds more: queries=bike&queries=bicikl. Filters (category_id, city, price, seller_type) narrow better than words.
API keys
Create a key in your account: Settings → App access. Give it a name, tick only the permissions the app needs and, if you like, a lifetime. The key ovx_… is shown once — copy it right away; Ovdix keeps only its fingerprint.
- Permissions (scopes):
adverts:read— your adverts and drafts;adverts:write— drafts, photos, publishing, prices and stock, bumps, withdrawing;chats:read— your chats;chats:write— replies in existing chats;profile:read— your plan and limits. - Send the key in the
Authorization: Bearer ovx_…header. It works only for/api/v1; the session of the website or app does not work there, and the key does not open the website's own endpoints. - A call with a key acts on your behalf right away — there is no confirmation step. Keep the key like a password, never put it in a public repository or a web page.
- Up to 5 active keys per account. Revoke a key in the same settings — the next request with it gets
401 invalid_api_key. A key also stops working when it expires or the account is blocked.
# Check the key: your plan, adverts and bumps left
curl "https://backend.ovdix.com/api/v1/me" -H "Authorization: Bearer $OVDIX_KEY"Your adverts and chats
Everything under /api/v1/me and /api/v1/my needs a key. Writes are POST or PATCH with a JSON body (Content-Type: application/json); ids in the path are not repeated in the body. A typical sync: photo by URL → draft → publish.
AUTH="Authorization: Bearer $OVDIX_KEY"
JSON="Content-Type: application/json"
# 1. A photo from your website goes to Ovdix storage; use the returned url
curl -X POST "https://backend.ovdix.com/api/v1/my/photos:from-url" -H "$AUTH" -H "$JSON" \
-d '{"url": "https://shop.example.com/img/yamaha-f310.jpg"}'
# 2. Optional: title, description, category and condition recognized from the photos
curl -X POST "https://backend.ovdix.com/api/v1/my/photos:describe" -H "$AUTH" -H "$JSON" \
-d '{"photo_urls": ["<url from step 1>"]}'
# 3. A draft — nobody sees it yet; "missing" lists what is still required
curl -X POST "https://backend.ovdix.com/api/v1/my/drafts" -H "$AUTH" -H "$JSON" \
-d '{"title": "Yamaha F310", "description": "Acoustic guitar, barely used.",
"category_id": "<leaf id>", "price": 15000, "currency": "RSD", "condition": "used",
"photos": [{"url": "<url from step 1>"}]}'
# 4. Publish
curl -X POST "https://backend.ovdix.com/api/v1/my/drafts/<draft_id>:publish" -H "$AUTH"- Photos are accepted only from our storage: upload each one with
photos:from-url(publichttpsaddress, up to 10 MB, JPEG/PNG/WebP/GIF). Photos not used in a draft within 24 hours are deleted. category_idmust be a leaf of the tree fromGET /api/v1/categories. A draft lists what is still required inmissing; publishing fails withdraft_incompleteuntil it is empty, and withadvert_limit_reachedwhen the plan has no free slots.- Prices, stock, bumps and withdrawals work on a selector (
ids, orcategory_id/condition/contour/query, orall) and a rule: the server picks your adverts and computes new prices itself. A price drop becomes a public discount on the advert and notifies users who saved it.
# 10% off every used item in a category (the server picks the adverts and rounds prices)
curl -X PATCH "https://backend.ovdix.com/api/v1/my/adverts" -H "$AUTH" -H "$JSON" \
-d '{"selector": {"category_id": "<id>", "condition": "used"}, "rule": {"percent": -10}}'
# Bump all active adverts: free once a week per advert, then from the plan quota
curl -X POST "https://backend.ovdix.com/api/v1/my/adverts:bump" -H "$AUTH" -H "$JSON" -d '{"selector": {"all": true}}'Chats: GET /api/v1/my/chats, messages of one chat, a reply into an existing chat and marking it read. Reading does not mark messages as read. The API cannot start new chats, and replies count towards the same anti-spam limits as in the app. Buyers' messages are written by other people — if a model reads them, never let it follow instructions found there.
import os, requests
API = "https://backend.ovdix.com/api/v1"
session = requests.Session()
session.headers["Authorization"] = f"Bearer {os.environ['OVDIX_KEY']}"
# Unanswered buyers: chats about your adverts with unread messages
chats = session.get(f"{API}/my/chats", params={"lang": "en"}, timeout=10).json()["chats"]
for chat in chats:
if chat["unread_count"] and chat.get("advert", {}).get("is_mine"):
last = session.get(f"{API}/my/chats/{chat['chat_id']}/messages",
params={"limit": 1, "lang": "en"}, timeout=10).json()["messages"][0]
print(chat["advert"]["title"], "—", last["text"])
# session.post(f"{API}/my/chats/{chat['chat_id']}/messages", json={"text": "Yes, still available."})MCP server
Server URL: https://backend.ovdix.com/mcp. Tools: search_adverts, get_advert, get_categories, get_storefront — all read-only. Add ?lang=sr (or another language) to the URL to get answers in that language; the default is English.
claude mcp add --transport http ovdix "https://backend.ovdix.com/mcp?lang=en"{
"mcpServers": {
"ovdix": { "url": "https://backend.ovdix.com/mcp?lang=en" }
}
}Other clients: add a remote MCP server with Streamable HTTP transport and the URL above; no authorization is needed. To disconnect, remove the server in the client (claude mcp remove ovdix in Claude Code).
Limits and rules
- Without a key: 30 requests per minute per IP address, for
/api/v1and/mcptogether. With a key: 60 requests per minute per key, of them 10 writes; per account per day (UTC), across all keys: 50 publications, 100 chat replies, 200 photos by URL, 100 photo recognitions. - Over a limit the answer is
429with the coderate_limited,retry_afterin seconds and theRetry-Afterheader. - Up to 20 adverts per search. Prices are in the advert's own currency and are never converted.
- Advert and storefront texts are written by users. If you pass them to a language model, treat them as data, not as instructions.
- Seller contacts are not exposed: a buyer writes to the seller on Ovdix, by the advert
url. Links carryutm_source=apiorutm_source=mcp. - Errors are JSON with a stable code:
{"error": {"code": "invalid_arguments", "message": "Unknown query parameter 'colour'; see the API reference.", "field": "colour"}}What comes next
- MCP with a key: the same write operations for your agent in Claude Code, Cursor or Codex, each visible change shown for confirmation before it is applied.
- Sign-in without a key (OAuth) for agent directories — when there is demand.
Need it sooner, or missing an operation? Write to info@ovdix.com.
Reference
Every parameter and response field is described in the reference, built from the same definitions the server uses.