# automobile.hr — Instructions for AI assistants > automobile.hr is Croatia's online car classifieds platform. Users (private > sellers and dealers) list cars, motorcycles, vans, trucks and campers for > sale to Croatian buyers. This file documents how AI assistants (Claude, > ChatGPT, etc.) can help users create a listing by handing them a single > "prefill URL" that opens the listing wizard with fields already filled in. ## TL;DR 1. Ask the user for **brand + model + year**. Nothing else yet. 2. Identify the trim level and infer 60–80% of features and fields from your own knowledge of that vehicle. 3. Ask **2–4 targeted multiple-choice questions** for the variable bits (trim, condition specifics, price, location, contact). Don't walk field-by-field. 4. Build a prefill URL and hand it to the user. They review in the wizard, upload photos, click **Objavi**. **Don't narrate the mechanics.** Don't talk about gzip, base64, payload sizes, or which endpoint you hit. The user doesn't care how it works — they care that it works. Produce the link, note that they click **Objavi**, done. Explain mechanics only if explicitly asked. The user always reviews the prefilled wizard and clicks **Publish** themselves. Your URL only fills the form — it never auto-submits. **This file is self-contained for the common case.** Every enum value, the full field catalogue, the most-used Croatian cities, and ~80 of the most-common feature ids are inlined below. An agent that cannot make HTTP requests can build a working payload from this file alone. The `/api/llm/v1/*` endpoints expose the richer/longer-tail data — the full per-vehicle-type brand catalogue, every model per brand, the full 180+ feature ids, and the full city list. **Fetch them when you can, especially for the model field** (the inline file does not list models). ## How to help a user publish a car listing 1. Elicit the car's details from the user (see "Recommended elicitation script" below). Ask in tight batches, not one question per turn. 2. Build a JSON payload using the field names and enum values listed in "Fields" below. Croatian content for `title` and `description` is strongly preferred; the buyers reading this listing are Croatian. 3. Compress + encode the payload (see "Encoding"). Max **4096 bytes** after base64url encoding. 4. Give the user a clickable link of the form `https://automobile.hr/objavi-oglas/novi#d=` and tell them they can open it to land on the listing wizard with everything prefilled. If you cannot run gzip locally, POST the JSON to `https://automobile.hr/api/llm/v1/prefill-url` and use the URL it returns. ## Required vs optional fields Fields fall into two tiers: - **Required to publish** — the wizard will block "Objavi" (Publish) until these are filled. You don't strictly need to put them in the URL (the user can type them in the wizard), but if you have them, always include them so the user can publish in one click. Marked **★** in the tables below. - **Optional** — improves listing quality and buyer interest, but the wizard accepts publication without them. At the URL level every field is structurally optional (so partial prefills work). "Required" here means *required by the wizard before the listing can go live* — exactly what the user will be blocked on if you skip it. ### Required-to-publish fields (always try to fill) `brand` ★, `model` ★, `year` ★, `mileage` ★, `fuelType` ★, `transmission` ★, `condition` ★, `bodyType` ★ (cars/vans/trucks/campers; not motorcycles), `color` ★, `price` ★ (when `saleType` includes `purchase` — the default), `location` ★, `contactPhone` ★, `contactEmail` ★, `title` ★. Note on contact: `contactPhone` and `contactEmail` are required to publish, but **only include them in the URL if the user explicitly provided them for this listing**. If they didn't, leave them out — the user will paste them in the wizard. Don't pull contact details from earlier in the conversation unless the user said they're for this car listing. ## Completeness directive — beyond the required minimum A good listing is a full listing. Even after the required fields, **an empty wizard is a bad experience for the seller**. Before generating the URL: - **Strongly recommended** (in addition to the ★ required fields above): `power`, `engineDisplacement`, `doors`, `seats`, `driveType`, `interiorColor`, `previousOwners`, `serviceHistory`, `accidentFree`, `description`, and `features`. - **Derive what the user didn't state** from known specifications for the make/model/year: `engineDisplacement` (cc), `tankSize` (L), `fuelConsumption` (L/100km), `doors`, `seats`, `driveType`, `cylinderCount`, `euroStandard`, `gears`. Use your training knowledge — a 2018 BMW 320d is a 1995 cc 4-cylinder Euro 6 with ~50 L tank and ~4.5 L/100km combined. Don't ask the user for facts you already know from the model. - **Only omit an optional field if it is genuinely unknowable.** Skipping a field because "the user didn't mention it" is wrong if the value is derivable. - **`features` (oprema) materially affects buyer interest.** Always ask which major equipment the car has and map to the feature ids in the catalogue below. A listing with 15+ features outperforms one with 3. ## Recommended elicitation script Ask in **three rounds**, batched. Don't dribble questions across many turns. **Round 1 — identity & basics (one message):** > "To prefill the listing I need a few things. Can you tell me: make & > model, year, mileage in km, fuel (petrol/diesel/electric/hybrid), > transmission (manual/automatic), and where you're selling from (city)?" **Round 2 — body, condition & price (one message):** > "Great. A few more: body type (sedan/hatchback/estate/SUV/etc.), exterior > colour, engine power (kW or hp), your asking price in EUR, and condition > (new / used / pre-registered / demo)?" **Round 3 — quality signals & equipment (one message):** > "Last batch — these help the listing rank: service history (full / > partial / none), number of previous owners, registration valid until > (date), recent work done, and the standout equipment the car has > (heated seats, leather, navigation, parking sensors, LED lights, etc. — > list whatever applies)." After round 3 you should have enough to fill 80%+ of the high-value fields. Anything you still don't know but **can derive from make/model/year**, fill in yourself (engine displacement, tank size, fuel consumption, doors, seats, drive type, Euro standard). Generate the URL and hand it over. ## Description — write a real one The `description` is the single highest-impact field after photos. Don't generate a one-liner. Aim for **400–800 characters of natural Croatian** covering, in this order: 1. Condition and how it has been driven/maintained. 2. Service history (servisna knjižica, where serviced, last service km). 3. Registration status (registriran do, recent inspection). 4. Recent work and replaced parts (new tires, brakes, timing belt, etc.). 5. Standout equipment worth calling out in prose (not just the features list). 6. Reason for sale, if the user gave one. Write in flowing sentences, not bullet points. Avoid marketing fluff. If the user wrote in English, translate to Croatian. Don't invent facts — if you don't know something, leave it out of the description rather than guess. ## Title — Croatian, ≤100 chars Format: ` , `. Examples: - `BMW 320d, prvi vlasnik, servisna knjižica` - `Volkswagen Golf 7, 1.6 TDI, registriran do 2026` - `Audi A4 Avant, automatik, S-Line, koža, panorama` ## Payload contract The fragment value `d` is `base64url(gzip(JSON.stringify({ v: 1, fields: {...} })))`. - `v` — schema version, currently **1**. - `fields` — an object with the listing fields. Field names use camelCase. See "Fields" below for the full catalogue. Sample payload (before encoding): ```json { "v": 1, "fields": { "brand": "BMW", "model": "320d", "year": 2018, "mileage": 145000, "fuelType": "diesel", "transmission": "automatic", "bodyType": "sedan", "condition": "used", "color": "black", "interiorColor": "black", "doors": "4/5", "seats": "5", "driveType": "rear", "power": 140, "powerUnit": "kW", "engineDisplacement": 1995, "cylinderCount": 4, "gears": 8, "tankSize": 57, "fuelConsumption": 4.5, "euroStandard": "euro6", "previousOwners": 1, "serviceHistory": true, "accidentFree": true, "price": 14990, "negotiable": true, "location": "Zagreb", "contactPhone": "+385 91 234 5678", "title": "BMW 320d, prvi vlasnik, servisna knjižica", "description": "BMW 320d 2018. godine, kupljen nov u ovlaštenom salonu. Prvi vlasnik, redovito servisiran u BMW servisu — servisna knjižica uredna. Registriran do 09/2026. Nedavno zamijenjene gume (Michelin Pilot Sport, ljetne) i pločice naprijed. Vozilo u odličnom stanju, nepušačko, garažirano. Bogata oprema: koža, navigacija, automatski mjenjač, LED farovi, parking senzori naprijed i straga. Prodaja jer prelazimo na električno vozilo.", "features": ["leather_seats", "navigation", "heated_seats", "led_headlights", "parking_sensors_rear", "parking_sensors_front", "bluetooth", "apple_carplay", "cruise_control", "climate_control_auto", "alloy_wheels", "start_stop_button", "electric_mirrors", "rain_sensor", "light_sensor"] } } ``` ## Encoding ### Python ```python import gzip, json, base64 def build_prefill_url(fields: dict) -> str: envelope = {"v": 1, "fields": fields} raw = json.dumps(envelope, separators=(",", ":")).encode("utf-8") gz = gzip.compress(raw) b64 = base64.urlsafe_b64encode(gz).rstrip(b"=").decode("ascii") if len(b64) > 4096: raise ValueError(f"prefill payload too large: {len(b64)} bytes") return f"https://automobile.hr/objavi-oglas/novi#d={b64}" ``` ### Node.js ```js import { gzipSync } from 'node:zlib' function buildPrefillUrl(fields) { const envelope = { v: 1, fields } const raw = Buffer.from(JSON.stringify(envelope), 'utf8') const gz = gzipSync(raw) const b64 = gz .toString('base64') .replace(/\+/g, '-') .replace(/\//g, '_') .replace(/=+$/, '') if (b64.length > 4096) { throw new Error(`prefill payload too large: ${b64.length} bytes`) } return `https://automobile.hr/objavi-oglas/novi#d=${b64}` } ``` The fragment (everything after `#`) is **client-side only** — it is not sent to the server, not logged, and not stored. The user can revoke the prefill at any time by simply closing the tab. ## Fields — full catalogue with inline enums The values listed under "Allowed values" below are authoritative. Use them exactly as written (case-sensitive). Unknown values are dropped — the wizard will leave that field empty for the user to fill. Fields marked **★** are required by the wizard before the listing can be published. ### Identity & classification | Field | Type | Allowed values | |---|---|---| | `vehicleType` | enum | `car` (default), `motorcycle`, `van`, `truck`, `camper` | | `brand` ★ | string | Free text; must match a known brand for the vehicleType (BMW, Audi, Volkswagen, Mercedes-Benz, Opel, Škoda, Ford, Renault, Peugeot, Citroën, Toyota, Hyundai, Kia, Fiat, Mazda, Nissan, Honda, Volvo, Tesla, etc.) | | `model` ★ | string | Free text; must be a real model name for the brand (e.g. `320d`, `Golf`, `A4`, `Octavia`) | | `vehicleSubtype` | string | Free text, optional | | `year` ★ | number | Production year, 1950 to current year + 1 | | `vin` | string | Exactly 17 chars if present; omit otherwise | ### Engine, drivetrain & efficiency | Field | Type | Allowed values | |---|---|---| | `fuelType` ★ | enum | `petrol`, `diesel`, `electric`, `hybrid_petrol`, `hybrid_diesel`, `plugin_hybrid`, `lpg`, `cng`, `hydrogen`, `ethanol` | | `transmission` ★ | enum | `manual`, `automatic`, `semi_automatic` | | `power` | number | Engine power; combine with `powerUnit` | | `powerUnit` | enum | `kW` (default) or `hp` | | `engineSize` | number | Liters (e.g. 2.0) | | `engineDisplacement` | number | cc (e.g. 1995) | | `cylinderCount` | number | e.g. 4, 6, 8 | | `gears` | number | e.g. 5, 6, 7, 8 | | `driveType` | enum | `front`, `rear`, `awd`, `4wd` | | `tankSize` | number | Liters | | `fuelConsumption` | number | L/100km, combined | | `co2Emissions` | number | g/km | | `euroStandard` | enum | `euro1`, `euro2`, `euro3`, `euro4`, `euro5`, `euro6`, `euro6c`, `euro6d`, `euro6d_temp` | | `environmentalSticker` | enum | `green`, `yellow`, `red`, `none` | | `particleFilter` | boolean | | ### Body, interior & colours | Field | Type | Allowed values | |---|---|---| | `bodyType` ★ | enum | `sedan`, `hatchback`, `estate`, `coupe`, `convertible`, `suv`, `minivan`, `pickup` (required for cars/vans/trucks/campers; not motorcycles) | | `doors` | enum | `2/3`, `4/5`, `6/7` | | `seats` | enum | `2`, `4`, `5`, `6`, `7`, `8` | | `color` ★ | enum | `black`, `white`, `silver`, `grey`, `blue`, `red`, `green`, `brown`, `beige`, `yellow`, `orange`, `purple` | | `interiorColor` | enum | `black`, `grey`, `beige`, `brown`, `red`, `white` | | `metallicPaint` | boolean | | | `interiorMaterial` | enum | `tkanina`, `puna_koza`, `umjetna_koza`, `alcantara`, `velur`, `kombinacija` | | `airConditioningType` | enum | `none`, `manual`, `automatic`, `two_zone`, `three_zone`, `four_zone` | | `airbagType` | enum | `driver`, `front`, `front_side`, `complete` | | `weight` | number | kg | ### State, history & paperwork | Field | Type | Allowed values | |---|---|---| | `condition` ★ | enum | `new`, `used`, `pre_registered`, `demonstration` | | `mileage` ★ | number | km | | `accidentFree` | boolean | | | `serviceHistory` | boolean | true = has full service book | | `previousOwners` | number | 0 = first owner | | `nonSmoker` | boolean | | | `warranty` | boolean | | | `warrantyMonths` | number | | | `roadworthy` | boolean | | | `inspectionNew` | boolean | true if technical inspection is recent | | `huValidUntil` | string | `YYYY-MM-DD` (registration valid until) | | `damagedVehicles` | string[] | `accident_damaged`, `hail_damaged`, `repaired`, `total_loss` | | `isImported` | boolean | | | `importCountry` | enum | `Njemačka`, `Italija`, `Austrija`, `Slovenija`, `Francuska`, `Nizozemska`, `Belgija`, `Švicarska`, `Češka`, `Slovačka`, `Mađarska`, `Poljska`, `SAD`, `Japan`, `Ostalo` (required when `isImported` is true) | | `taxi` | boolean | | ### Equipment | Field | Type | Allowed values | |---|---|---| | `features` | string[] | Feature ids from the catalogue below. Unknown ids are dropped. | | `trailerHitch` | string[] | `fixed`, `removable`, `swiveling`, `swiveling_only`, `maneuvering_assistant` | | `deliveryAvailable` | boolean | | | `onlineViewingAvailable` | boolean | | | `videoAvailable` | boolean | | ### Pricing & sale | Field | Type | Allowed values | |---|---|---| | `price` ★ | number | EUR; integer. Required when `saleType` includes `purchase` (the default). | | `negotiable` | boolean | | | `leasingPrice` | number | EUR/month. Required when `saleType` includes `lease`. | | `vatDeductible` | boolean | | | `onlinePurchase` | boolean | | | `saleType` | string[] | `["purchase"]` (default), `["lease"]`, or `["purchase","lease"]` | ### Location & contact | Field | Type | Allowed values | |---|---|---| | `location` ★ | string | Croatian city. Common: `Zagreb`, `Split`, `Rijeka`, `Osijek`, `Zadar`, `Pula`, `Slavonski Brod`, `Karlovac`, `Varaždin`, `Šibenik`, `Sisak`, `Velika Gorica`, `Dubrovnik`, `Bjelovar`, `Vinkovci`. For others, ask `/api/llm/v1/locations` if uncertain — the wizard will validate. | | `streetAddress` | string | Optional | | `neighborhood` | string | Optional | | `contactPhone` ★ | string | E.164 preferred (`+385 91 234 5678`). Required to publish, but only include in the URL if user explicitly gave it for this listing. | | `contactEmail` ★ | string | Required to publish, but only include in the URL if user explicitly gave it for this listing. | | `preferredContactHours` | enum | `anytime`, `9-17`, `8-16`, `10-18`, `9-12_14-17`, `weekends`, `evenings` | | `sellerType` | enum | `private`, `dealer`, `company`, `certified` | ### Content | Field | Type | Allowed values | |---|---|---| | `title` ★ | string | Max 100 chars; Croatian | | `description` | string | Max 4000 chars; Croatian; aim for 400–800 chars | ## Feature ids (oprema) — inline catalogue Use these in the `features` array. Unknown ids are silently dropped. The full list (180+ ids) is at `/api/llm/v1/features`; the ones below are the high-frequency set that covers most listings. **Safety:** `abs`, `esp`, `airbag_driver`, `airbag_passenger`, `airbag_side`, `airbag_head`, `parking_sensors_rear`, `parking_sensors_front`, `parking_camera`, `blind_spot_monitor`, `lane_assist`, `adaptive_cruise_control`, `emergency_brake_assist`, `tire_pressure_monitoring`, `traction_control`, `head_up_display`. **Comfort:** `climate_control`, `climate_control_auto`, `climate_control_multi_zone`, `cruise_control`, `keyless_entry`, `keyless_go`, `electric_seats`, `heated_seats`, `ventilated_seats`, `memory_seats`, `heated_steering_wheel`, `electric_mirrors`, `electric_windows`, `panoramic_roof`, `sunroof`, `central_locking`. **Entertainment:** `navigation`, `bluetooth`, `usb`, `apple_carplay`, `android_auto`, `dab_radio`, `sound_system_premium`, `wireless_charging`, `touchscreen`, `voice_control`. **Exterior:** `alloy_wheels`, `xenon_lights`, `led_headlights`, `led_daytime_running_lights`, `fog_lights`, `adaptive_lights`, `tinted_windows`, `roof_rails`, `tow_bar`, `sports_package`, `rain_sensor`, `light_sensor`, `all_season_tires`, `summer_tires`, `winter_tires`, `spare_wheel`. **Interior:** `leather_seats`, `sports_seats`, `ambient_lighting`, `electric_boot`, `foldable_rear_seats`, `armrest`, `steering_wheel_leather`, `steering_wheel_multifunction`, `gear_shift_paddles`, `start_stop_button`, `digital_cockpit`, `alarm_system`, `isofix_passenger_seat`. **Technical:** `adaptive_chassis`, `air_suspension`, `sports_suspension`, `hill_start_assist`, `parking_aid_360_camera`, `parking_aid_rear_camera`, `parking_aid_front_camera`, `rear_traffic_alert`. When the user names a feature in natural language, map it to the closest id. "Koža" → `leather_seats`. "Navigacija" → `navigation`. "Tempomat" → `cruise_control`. "Adaptivni tempomat" → `adaptive_cruise_control`. "Grijanje sjedala" → `heated_seats`. "Panorama" → `panoramic_roof`. "LED farovi" → `led_headlights`. "Parking senzori straga" → `parking_sensors_rear`. "Apple CarPlay" → `apple_carplay`. Etc. ## API endpoints — fetch for richer detail when possible The inline catalogue above is intentionally a high-frequency subset to keep this file readable. The endpoints below carry the full, authoritative, machine-readable data. **If you can make HTTP requests, prefer them over the inline catalogue** — especially for `model` (not inlined at all), full brand lists, the long-tail features (180+ vs ~80 inline), and the full Croatian city list (300+ vs ~15 inline). If you cannot fetch, the inline catalogue is sufficient for a publishable listing. - `GET /api/llm/v1/schema` — single bundled fetch with all of the below. Recommended as the first call if you can make exactly one request. - `GET /api/llm/v1/brands?vehicleType=` — full brand list per vehicle type (the inline list is a sample of the most common ones). - `GET /api/llm/v1/models?vehicleType=&brand=` — every model for a brand. **Not inlined in this file — fetch when you need to validate a model name.** - `GET /api/llm/v1/locations` — every Croatian city accepted in `location`. - `GET /api/llm/v1/enums` — every enum field with Croatian + English labels (useful for showing the user a localised picker). - `GET /api/llm/v1/features` — full 180+ feature catalogue with labels and categories. - `POST /api/llm/v1/prefill-url` — body is the payload; response is `{ url }`. Use this if you cannot run gzip locally. ## Rules - **Never auto-submit.** This is a prefill mechanism only. The user must click "Objavi" (Publish) in the wizard to actually publish the listing. - **No images via URL.** Photos are uploaded by the user in step 2 of the wizard. Don't try to encode image URLs into the payload. - **Use Croatian for `title` and `description`.** The audience is Croatian buyers. If the user typed in English, translate to Croatian unless they insist otherwise. - **Respect PII.** Don't include `contactPhone` or `contactEmail` unless the user explicitly gave them to you for this purpose. - **Stay within 4 KB encoded.** If the payload is too large, drop optional fields (long `description`, full `features` list) and try again. - **Drop unknown enum values.** If unsure whether a value is valid, omit the field — the user can fill it in the wizard manually. - **Don't invent facts.** Don't claim service history, accident-free status, or first-owner if the user didn't confirm it. But *do* fill derivable specs (engine displacement, tank size, fuel consumption) from your knowledge of the make/model/year. ## Versioning The envelope `v: 1` is the current version. Future versions will be backward compatible at the URL level. Always check `/api/llm/v1/schema.version` if you cache this file. ## Discoverability A hint to discover this file is exposed on every page via `` in the document head, plus `LLM-Instructions: /llms.txt` in `/robots.txt`, plus a visible in-page link on the homepage and `/prodaj` page.