Kufar APIkufar.by ↗
Search kufar.by classified ads, fetch offer details, browse categories, and get autocomplete suggestions via a structured JSON API covering all of Belarus.
What is the Kufar API?
The Kufar.by API exposes 5 endpoints covering Belarus's largest classifieds marketplace, letting you search ads by text, price, region, and condition; retrieve full offer details including images, prices in multiple currencies, and seller metadata; browse the complete category tree in Russian and Belarusian; and pull per-category match counts. The search_offers endpoint returns paginated ad summaries with cursor-based continuation and site-wide match totals.
curl -X GET 'https://api.parse.bot/scraper/246eb0a4-34ab-46cc-a4bc-52b0cffb0dca/search_offers?sort=newest&query=macbook' \ -H 'X-API-Key: $PARSE_API_KEY'
Typed, relational, agent-ready
A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.
- Fully typed · autocompletes
- Objects link to objects
- Typed errors & pagination
Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:
uv add parse-sdk uv run parse init uv run parse add --marketplace kufar-by-api
uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.
"""Walkthrough: Kufar.by classifieds — search, drill into details, browse categories."""
from parse_apis.kufar_by_api import Kufar, SortOrder, Condition, OfferNotFound
client = Kufar()
# Search for used MacBooks, newest first; cap total items fetched.
for item in client.offer_summaries.search(
query="macbook", sort=SortOrder.NEWEST, condition=Condition.USED, limit=5
):
print(item.title, f"{item.price_byn} BYN", item.region)
# Drill down: take the first hit and fetch its full detail page.
hit = client.offer_summaries.search(query="macbook", limit=1).first()
if hit is not None:
offer = hit.details()
print(offer.title, offer.description[:120] if offer.description else "")
for p in offer.prices:
print(f" {p.currency}: {p.price}")
for param in offer.parameters[:5]:
print(f" {param.label}: {param.value_label}")
# Point lookup by ad_id discovered from the search above.
if hit is not None:
try:
detail = client.offers.get(ad_id=hit.ad_id)
print(detail.title, detail.seller_name)
except OfferNotFound:
print("Ad was removed since the search.")
# Per-category counters for the same query.
breakdown = client.category_breakdowns.count(query="macbook")
print(f"{breakdown.total} total ads across {len(breakdown.categories)} categories")
for cat in breakdown.categories[:3]:
print(f" {cat.category} ({cat.parent}): {cat.count}")
# Browse the full category tree.
for category in client.categories.list(limit=5):
subs = ", ".join(s.name for s in category.subcategories[:3])
print(f"{category.name}: {subs}")
# Autocomplete suggestions for a partial query.
for suggestion in client.suggestions.search(query="macbo", limit=5):
print(suggestion.text, suggestion.preferred_category_id)
print("exercised: offer_summaries.search / details / offers.get / category_breakdowns.count / categories.list / suggestions.search")
Searches public classified ads across all of Belarus by free-text query with optional category, region, price range, condition and sort controls. Returns one page of ad summaries (grain: one ad per item) plus the site's total match count. Pagination is cursor-based: each response carries next_cursor (null when the last page is reached); pass it back unchanged as cursor together with the same query, filters and size to get the following page. Omitting cursor returns the first page. Prices are in Belarusian rubles (BYN) and US dollars as published by the site. An empty query lists the newest ads site-wide. A query with no matches is a valid empty result (total 0, items []). One upstream request per call.
| Param | Type | Description |
|---|---|---|
| size | integer | Number of ads per page, 1..200 (values above 200 are clamped to 200). |
| sort | string | Result ordering. |
| query | string | Free-text search phrase. Omitted or empty = all ads. |
| cursor | string | Opaque continuation token from a previous response's next_cursor. Must be used with the same query, filters and size. |
| condition | string | Item condition filter. Omitted = any condition. |
| price_max | string | Maximum price in whole BYN (non-negative integer string). |
| price_min | string | Minimum price in whole BYN (non-negative integer string). |
| region_id | string | Numeric site region id; the site's regions include Minsk city (7). Confirmed with 7 in testing. Omitted = all of Belarus. |
| category_id | string | Numeric site category id (e.g. as returned in items[*].category_id or autocomplete_search.suggestions[*].preferred_category_id). Omitted = all categories. |
{
"type": "object",
"fields": {
"count": "integer, ads in this page",
"items": "array of ad summaries: ad_id (string, use with get_offer), title, url, price_byn (number, BYN), price_usd (number), category_id, category (Russian label), region, area, condition (Russian label), listed_at (ISO 8601 UTC), type, company_ad (boolean), seller_name, phone_hidden (boolean), delivery_enabled (boolean), images (array of thumbnail URLs)",
"query": "echo of the search phrase used",
"total": "integer, total ads matching on the site",
"has_more": "boolean, true when next_cursor is present",
"next_cursor": "string continuation token or null when no further page"
},
"sample": {
"data": {
"count": 1,
"items": [
{
"url": "https://www.kufar.by/item/1085524845",
"area": "Могилев",
"type": "sell",
"ad_id": "1085524845",
"title": "MacBook Air m1",
"images": [
"https://rms.kufar.by/v1/list_thumbs_2x/adim1/882d4eef-bdd7-4aac-a490-777e627e7e77.jpg"
],
"region": "Могилевская область",
"category": "Ноутбуки",
"condition": "Б/у",
"listed_at": "2026-09-17T20:28:28Z",
"price_byn": 1400,
"price_usd": 463.15,
"company_ad": false,
"category_id": "16040",
"seller_name": "Продавец",
"phone_hidden": false,
"delivery_enabled": true
}
],
"query": "macbook",
"total": 2772,
"has_more": true,
"next_cursor": "eyJ0IjoiYWJzIiwiZiI6dHJ1ZSwicCI6MiwicGl0IjoiMjk4MjgwNDEifQ=="
},
"status": "success"
}
}About the Kufar API
Search and Pagination
The search_offers endpoint accepts a free-text query, optional category_id, region_id (e.g. 7 for Minsk city), condition, price_min/price_max in whole BYN, sort order, and a size of 1–200 ads per page. Each response includes an items array of ad summaries (with ad_id, title, url, price_byn, price_usd, and category_id), a total match count, and a next_cursor token for fetching the next page. To walk through all results, pass cursor from the previous response unchanged alongside the same query and filter parameters.
Offer Details and Category Data
get_offer takes a single ad_id (the numeric identifier returned in search_offers items) and returns the full public ad: title, description, a prices array with every currency the site publishes, images as full-size URLs, area and region location labels, seller as a keyed object of labeled parameters, and a category label in Russian. Seller phone numbers are not included — the site gates those behind a click. list_categories returns the full two-level category tree with each category's category_id, Russian name, Belarusian name_by, and a subcategories array; some subcategories carry a redirect_to flag indicating the site treats them as aliases.
Counters and Autocomplete
count_offers_by_category mirrors the sidebar counts shown on a kufar.by search results page: for a given query, region_id, condition, and price range, it returns every leaf category with at least one match, its Russian label, and its parent_id. The total field is the sum across all returned categories. autocomplete_search takes a partial query string and returns the site's typeahead suggestions — each suggestion carries a text phrase and a preferred_category_id (or null) — along with any category_suggestions.
The Kufar API is a managed, monitored endpoint for kufar.by — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when kufar.by changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official kufar.by API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Monitor BYN and USD price trends for a specific product category across all Belarusian regions using
search_offerswithprice_min/price_maxfilters - Build a cross-category inventory tracker by combining
count_offers_by_categorytotals with daily snapshots - Fetch full ad details with
get_offerto populate a comparison tool showing multi-currency prices and item condition - Implement a Belarus-localized search widget with live suggestions using
autocomplete_searchandpreferred_category_idhints - Enumerate the kufar.by category taxonomy in both Russian and Belarusian via
list_categoriesfor localization or mapping to another classification system - Paginate through all active listings in a leaf category using cursor-based pagination from
search_offersto detect new or removed ads
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 200 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
| Team | $300/mo | 20,000 | 300 req/min |
| Company | $1,000/mo | 100,000 | 500 req/min |
Each endpoint has a fixed posted price per successful call — most fall between 1 and 10 credits — shown on this API's page before you run it. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does kufar.by have an official public developer API?+
What does `get_offer` return, and does it include seller phone numbers?+
prices array), full-size image URLs, area and region labels, and seller parameters as labeled key-value pairs. Seller phone numbers are not included — the site requires an additional user action to reveal them, so they are outside what the endpoint exposes.How does cursor-based pagination work in `search_offers`?+
next_cursor string (or null when results are exhausted) and a has_more boolean. To fetch the next page, pass the next_cursor value as the cursor parameter in your next request, keeping all other query parameters — including query, region_id, condition, and price range — identical. Changing any filter while reusing a cursor will produce unpredictable results.Are ad details like view counts, favourite counts, or ad age returned?+
get_offer response covers title, description, prices, images, location, and seller parameters. View counts, favourite counts, and publication timestamps are not fields the endpoint exposes. You can fork this API on Parse and revise it to add those fields if the underlying ad page surfaces them.Is coverage limited to Belarus, and are all kufar.by categories included?+
search_offers and count_offers_by_category cover the full Belarus geography; region_id narrows to one of the site's regions (e.g. 7 for Minsk city). list_categories returns the complete two-level category tree including subcategory aliases. The API does not cover kufar.by's separate real-estate rental or job-board flows as distinct structured endpoints; those ads appear in general search results but without their domain-specific structured fields. You can fork this API on Parse and revise it to add dedicated real-estate or jobs endpoints.