POST /v1/catalog/parse-query
Parse a natural-language car search into catalogue filters
Parse a natural-language car search into catalogue filters
Turns free text in Ukrainian, Russian, Polish or English ("diesel estate under 15k, automatic, 2018+, from Germany") into CatalogQuery filters plus human-readable chips. A deterministic parser handles typical queries (makes/models with typos, years, prices with currency conversion to EUR, mileage, fuel, gearbox, body, drive, colour, countries, VAT, freshness); complex queries go to Claude with a strict output schema, a timeout and a fallback to the rule-based result. Makes are always validated against the catalogue taxonomy. demo:true means no model is configured. AI parsing has its own per-key rate limit and daily token budget (then rules only). Requires scope read:listings.
- Authentication: header
Authorization: Bearer rv_live_...(API keys and scopes) - Required scope:
read:listings
openapi.json).Request body
| Field | Type | Required | Description |
|---|---|---|---|
text | string | yes | Free-text query in Ukrainian, Russian, Polish or English, e.g. "diesel estate under 15k, automatic, 2018+, from Germany". |
locale | "uk" | "pl" | "en" | no | Language of chip labels. |
Responses
200
Parsed filters.
application/json · Schema: CatalogParseResponse
| Field | Type | Required | Description |
|---|---|---|---|
query | object | yes | Catalog filters (contract catalog-search). Prices are EUR, mileage km, power kW. |
query.q | string | no | |
query.make | string[] | no | |
query.model | string[] | no | |
query.yearFrom | integer | null | no | |
query.yearTo | integer | null | no | |
query.priceFrom | integer | null | no | |
query.priceTo | integer | null | no | |
query.mileageFrom | integer | null | no | |
query.mileageTo | integer | null | no | |
query.powerFrom | integer | null | no | |
query.powerTo | integer | null | no | |
query.fuel | "petrol" | "diesel" | "hybrid" | "phev" | "ev" | "lpg" | "cng" | "hydrogen" | "other"[] | no | |
query.gearbox | "manual" | "automatic" | "cvt" | "robot" | "other"[] | no | |
query.body | "sedan" | "hatchback" | "wagon" | "suv" | "crossover" | "coupe" | "convertible" | "minivan" | "van" | "pickup" | "truck" | "motorcycle" | "other"[] | no | |
query.drive | "fwd" | "rwd" | "awd" | "4wd"[] | no | |
query.color | string[] | no | |
query.country | "de" | "at" | "nl" | "be" | "lu" | "fr" | "dk" | "se" | "no" | "fi" | "ee" | "lv" | "lt" | "pl" | "cz" | "sk" | "it" | "es"[] | no | |
query.source | string[] | no | |
query.sellerType | "dealer" | "private" | "unknown"[] | no | |
query.vat | "deductible" | "included" | "unknown"[] | no | |
query.withPhotos | boolean | null | no | |
query.postedWithinDays | integer | null | no | |
query.features | "tow_hitch" | "heat_pump" | "panorama_roof" | "apple_carplay" | "android_auto" | "camera" | "camera_360" | "heated_seats" | "heated_steering" | "ventilated_seats" | "head_up" | "adaptive_cruise" | "navigation" | "keyless" | "electric_tailgate" | "leather"[] | no | |
query.batteryFrom | integer | null | no | |
query.batteryTo | integer | null | no | |
query.sort | "relevance" | "newest" | "price_asc" | "price_desc" | "mileage_asc" | "year_desc" | "landed_asc" | "deal_score" | no | |
chips | object[] | yes | What was understood, in reading order. |
chips[].field | string | no | CatalogQuery field the chip stands for (price/year/mileage/power for ranges). |
chips[].value | string | no | Value for list fields, e.g. "diesel" or "bmw/x5". |
chips[].label | string | no | Human label in the requested locale, e.g. "Diesel", "up to €15,000". |
understood | boolean | yes | At least one filter (or a sort) was recognised. |
method | "rules" | "ai" | "ai_cache" | yes | rules — deterministic parser; ai — Claude (merged with rules); ai_cache — cached model parse. |
demo | boolean | yes | true — no AI model is configured, the rule-based parser only (demo mode). |
ai_skipped | "not_configured" | "disabled" | "not_needed" | "rate_limited" | "budget_exhausted" | "timeout" | "error" | "invalid" | "refusal" | null | yes | Why the model was not used (null when it was). |
ignored | string[] | yes | Words that could not be turned into a filter. |
unsupported_markets | string[] | yes | Markets outside the EU catalogue the query asked for (us, kr, cn ...): not searchable here. |
price_original | object | yes | Price as written in the query (before conversion to EUR at the ECB/NBU rate). |
price_original.min | number | no | |
price_original.max | number | no | |
price_original.currency | string | yes | |
price_original.assumed | boolean | no | No currency was named: EUR assumed. |
catalog_url | string | null | yes | Public site catalogue page with these filters (null if not configured). |
took_ms | integer | yes |
400
Invalid request parameters or body (code validation_error).
application/problem+json · Schema: Problem
401
Missing, malformed, unknown, revoked or expired API key (code unauthorized).
application/problem+json · Schema: Problem
403
The API key lacks the scope required by this endpoint (code insufficient_scope).
application/problem+json · Schema: Problem
429
Rate limit exceeded for the tenant plan (code rate_limited). Wait Retry-After seconds.
application/problem+json · Schema: Problem
503
The catalogue is not configured on this server.
application/problem+json · Schema: Problem