Import API
checking…
Developer documentation

Import API

Keep your Mi Taller inventory in step with your DMS or stock system. Create and update vehicles, push complete inventories, manage photos — through a versioned REST API scoped to your workshop.

REST + JSONPredictable endpoints, JSON in and out, stable error codes.
Workshop scopedEvery key belongs to one workshop and can only see that workshop's cars.
Same vocabulary as the siteAccepted values are exactly what the Add-Vehicle form offers, labelled in five languages.
Safe syncAll-or-nothing validation, stale-update protection, unlist-never-delete in complete syncs.

The API is for professional sellers, dealer groups, DMS vendors and integration partners. Records you create appear on mitaller.us under your workshop, exactly like cars added by hand.

Scope. API records are scoped to the authenticated workshop. A key can never read or change another workshop's inventory, and a workshop owner with several workshops needs one key per workshop.

Quickstart

1. Create an API key

Sign in to {link}, pick the workshop, give the key a name and copy it. The key is shown once; if you lose it, revoke it and create another.

2. Test authentication

curl https://api.mitaller.us/v1/me \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Accept: application/json"

3. Create a vehicle

curl -X POST https://api.mitaller.us/v1/vehicles \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "external_id": "STOCK-4821",
  "external_updated_at": "2026-09-05T08:30:00Z",
  "make": "Volkswagen",
  "model": "Golf",
  "year": 2022,
  "vin": "WVWZZZAUZNW123456",
  "license_plate": "1-ABC-123",
  "mileage": 41200,
  "first_registration": "2022-03-15",
  "fuel_type": "petrol",
  "gearbox_type": "dct",
  "body_type": "hatchback",
  "power_hp": 150,
  "num_doors": 5,
  "num_seats": 5,
  "color": "gray",
  "interior_material": "fabric",
  "vehicle_condition": "used",
  "asking_price": 24950,
  "is_tax_vehicle": true,
  "short_description": "Golf 1.5 TSI Life, first owner, full history",
  "seller_description": "Serviced at the dealership, two keys, winter tyres included.",
  "features": [
    "appleCarplay",
    "androidAuto",
    "adaptiveCruiseControl",
    "ledHeadlights",
    "alloyWheels"
  ],
  "parking_assist": [
    "sens_front",
    "sens_rear",
    "cam_rear"
  ],
  "image_urls": [
    "https://cdn.example-dealer.be/stock/4821/front.jpg",
    "https://cdn.example-dealer.be/stock/4821/interior.jpg"
  ]
}'

The response is the stored vehicle including its uuid, public_url, currency and photos, plus a warnings array when something non-fatal happened (a photo that could not be fetched, a model that was created).

Base URL & versioning

https://api.mitaller.us/v1

The major version is part of the path. Backwards-incompatible changes get a new major version; /v1 keeps its behaviour. Additive changes (new optional fields, new enumeration values) can appear within v1 — read GET /v1/options rather than hard-coding lists.

Paths are shown without a trailing slash; one is accepted.

Authentication

Bearer-token authentication with a workshop API key. Keys start with wsk_.

Authorization: Bearer wsk_…

X-API-Key: wsk_… is accepted as an alternative header. A key is either read-write or read-only; a read-only key gets 403 read_only_key on any write.

Credential security. Never put an API key in browser-side JavaScript, a public repository, a screenshot or a support ticket. Revoke a key the moment you suspect it leaked — revocation is immediate.

Request headers

HeaderValuePurpose
AuthorizationBearer wsk_…Authenticates the workshop.
Content-Typeapplication/jsonFor JSON bodies. Photo file uploads use multipart/form-data.
Acceptapplication/jsonResponses are always JSON.

Vehicle data model

Fields accepted on POST, PUT and PATCH. Responses return the same names, plus read-only uuid, status (published / unlisted), public_url, currency, images, for_sale_since and created_at.

This is the complete set: 48 fields — the same ones the Add-Vehicle form offers — with 12 enumerations, 106 equipment values and 6 parking aids. Every accepted value is listed on this page and in GET /v1/options; nothing else is accepted.
FieldTypeCreateDescription
Identity
external_idstring ≤120recommendedYour own stable id for the vehicle (stock number, DMS id). Lets you address the car by it and enables upsert and inventory sync.
external_updated_atdatetimenoWhen your system last changed the vehicle. An older timestamp than the one stored is rejected with 409 stale_update.
license_platestring ≤20noMust be unique across the platform.
vinstring (17)noChassis number, unique across the platform. Stored upper-case.
Make, model & registration
make / make_idstring / integeryesBrand, by name (case-insensitive) or id. GET /v1/makes.
model / model_idstring / integeryesModel within the make. Unknown names are rejected unless create_missing_model is true.
create_missing_modelbooleannoAdd an unknown model name under the make instead of failing. Default false.
vehicle_type / vehicle_type_idstring / integernoCar, Motorcycle, SUV, Truck, Van. Default Car.
yearintegeryesModel year, 1990–2027.
first_registrationdatenoYYYY-MM-DD.
colorstring ≤50noUse a value from the color enumeration to get it translated; other words are shown as sent.
whiteblacksilvergrayblueredgreenyelloworangebrownbeigegoldpurplepinkotherlabels ↓
mileageintegernoOdometer reading, in mileage_unit.
mileage_unitenumnokm (default) or mi. Use mi for US/UK cars sold abroad; the site shows the unit as sent.
Engine & drivetrain
motor_typestring ≤100noEngine designation, e.g. "2.0 TDI 150hp".
fuel_typeenumnoSee enumerations.
petroldieselelectrichybrid_petrolhybrid_dieselphev_petrolphev_diesellpgcnghydrogenmild_hybridotherlabels ↓
power_hp / power_kwintegernoSend either; the other is derived.
cylinder_capacityinteger ccnoEngine displacement in cm³, e.g. 1998.
gearbox_typeenumnoManual, automatic, semi-automatic, CVT or single-speed (electric).
manualautomaticcvtdctsemi_autolabels ↓
drivetrainenumnofront, rear or 4wd.
4wdfrontrearlabels ↓
emission_standardenumnoEuro class.
euro0euro1euro2euro3euro4euro5euro6euro6beuro6ceuro6deuro6d_tempotherlabels ↓
co2_gkmintegernoCO₂ in g/km.
battery_capacity_kwhdecimal kWhnoElectric vehicles: usable battery capacity, e.g. 77.4. Shown instead of the Euro norm when fuel_type is electric.
battery_soh_pctinteger 0–100noBattery state of health in %.
battery_certificate_urlurlnoLink to the battery health certificate; shown as a clickable link on the listing.
Body, dimensions & wheels
body_typeenumnoBody style as shown in the listing filters.
sedanhatchbackestatecoupeconvertiblesuvcrossovermpvpickupvanotherlabels ↓
num_doors / num_seatsintegernoDoors 1–9, seats 1–99.
weightinteger kgnoKerb weight.
steering_positionenumnolhd or rhd.
tyre_size / bolt_pattern / et_offsetstringnoe.g. "225/45R17", "5x112", "+35".
Interior & comfort
interior_colorstring ≤50noFree text, e.g. "black".
interior_materialenumnoUpholstery.
alcantarafabricartificial_leatherpartial_leatherfull_leathervelourlabels ↓
air_conditioningenumnoNone, manual or automatic climate control (1–4 zones).
acNoneacManualac2Zoneac3Zoneac4Zonelabels ↓
airbagsenumnoHow many airbags are fitted.
airbagDriverairbagFrontairbagFrontSideairbagFulllabels ↓
Equipment
featuresarray[string]noEquipment slugs from the catalogue below. Unknown slugs are rejected. Sending [] clears the list.
parking_assistarray[string]noParking aid slugs from the catalogue below.
Sale & condition
is_for_salebooleannoDefault true on create. false takes the car off the marketplace but keeps it.
asking_pricedecimalnoIn the workshop's currency (returned as `currency`). Plain number, not cents.
is_margin_vehicle / is_tax_vehiclebooleannoVAT treatment: margin scheme or VAT-deductible.
vehicle_conditionenumnoNew, demo, used, damaged…
factory_newnew_conditionnew_with_damageusedused_with_damagepartslabels ↓
num_ownersintegernoPrevious owners, 0–99.
maintenance_historyenumnoService book status.
nonedealershipplatformbothlabels ↓
carpass_urlurlnoCar-Pass document link (Belgium).
short_descriptionstring ≤120noOne-liner on listing cards.
seller_descriptiontextnoFull description.
soldbooleannotrue = the car was sold: it goes off sale and is reported as status "sold" with sold_at.
sold_viaenumnoplatform or elsewhere (default elsewhere). Only with sold: true.
platformelsewherelabels ↓
queue_if_fullbooleannoDefault true: with every slot taken, a car asked to go on sale waits in the queue (status "queued") instead of failing with 403.
Photos
image_urlsarray[url] ≤30noPhotos to download from your servers, in display order. When present it replaces the whole photo set; omit to leave photos alone.
Identifier. Use a permanent id from your DMS as external_id — never a stock position or display order. It is what makes upsert, GET /v1/vehicles/{ref} by your id, and inventory sync work.

Endpoints

Account

GET/v1/meWho am IThe workshop behind the key, sale-slot usage, vehicle counts.
GET/healthHealthNo authentication.

Reference (no key needed)

GET/v1/optionsAll accepted valuesEvery enumeration, equipment slug, parking value and vehicle type, labelled in en/nl/fr/es/pt.
GET/v1/featuresEquipment catalogueJust the equipment slugs with their groups.
GET/v1/makes?search=MakesOptional `search` and `vehicle_type_id`.
GET/v1/makes/{make_id}/modelsModels of a make

Vehicles

GET/v1/vehiclesList`status=published|queued|unlisted|sold|all`, `external_id=`, `updated_since=` (change feed), `limit` (≤200), `offset`.
POST/v1/vehiclesCreate or upsert201 on create. If `external_id` already exists for your workshop the vehicle is updated and 200 is returned.
GET/v1/vehicles/{ref}Get one`ref` is our uuid or your external_id.
PATCH/v1/vehicles/{ref}Update some fieldsOmitted fields keep their value.
PUT/v1/vehicles/{ref}ReplaceOmitted optional fields are cleared.
DELETE/v1/vehicles/{ref}DeletePermanent, photos included. Prefer PATCH {"is_for_sale": false} to unlist.
POST/v1/vehicles/syncSync a whole inventoryUp to 200 vehicles per call, all-or-nothing validation, optional `complete` mode.
GET/v1/vehicles/deleted?since=Deleted vehiclesVehicles of yours that were deleted after `since`, with uuid and external_id.

Slots

GET/v1/slotsSlots and waiting listlimit, used, available, queued, slots_needed, the cars for sale and the waiting list in order.
POST/v1/vehicles/publishPut vehicles on sale`{"vehicles": [uuid or external_id, …]}` in your order: free slots are filled, the rest waits in the queue.
POST/v1/vehicles/unpublishTake vehicles off saleAlso removes them from the queue; freed slots go to the next cars waiting.

Webhooks

GET/v1/webhooksList webhooksYour registered URLs, events and delivery health.
POST/v1/webhooksRegister a webhook`{"url": "https://…", "events": […]}` — the answer carries the signing `secret`, once.
PATCH/v1/webhooks/{id}Change a webhook`url`, `events`, `include_own_changes`, `is_active`; `rotate_secret: true` returns a new secret.
DELETE/v1/webhooks/{id}Delete a webhook
POST/v1/webhooks/{id}/testSend a test pingQueues a signed `ping` event to the URL.
GET/v1/webhooks/{id}/deliveriesDelivery logThe last 50 deliveries with status, attempts and last error.

Photos

GET/v1/vehicles/{ref}/imagesList photosOrder 0 is the main photo.
POST/v1/vehicles/{ref}/imagesAdd a photoJSON `{"url": …}` or multipart `image` file; optional `order`.
PUT/v1/vehicles/{ref}/images/orderReorder`{"ids": […]}` — every photo id exactly once.
DELETE/v1/vehicles/{ref}/images/{id}Delete a photoRemaining photos are renumbered.

Full request and response schemas, with every enumeration inlined: Swagger UI · ReDoc · openapi.json.

List response

{
  "count": 37, "limit": 50, "offset": 0, "next_offset": null,
  "results": [ { "uuid": "…", "external_id": "STOCK-4821", "status": "published", … } ]
}

Upsert & stale updates

POST /v1/vehicles with an external_id that your workshop already uses updates that vehicle (HTTP 200) instead of creating a second one (HTTP 201). This makes a naive "push everything every night" integration idempotent.

When you also send external_updated_at, an update whose timestamp is older than the one stored is refused with 409 stale_update, so a delayed event can never overwrite a newer one. Inside a sync such a vehicle is reported as skipped_stale and the rest proceeds.

PATCH changes only the fields you send. PUT is a full replacement: optional fields you leave out are cleared. Both accept the same body as create.

Inventory sync

POST /v1/vehicles/sync upserts a whole inventory in one call (≤200 vehicles; call it repeatedly for more). Every vehicle needs an external_id.

{
  "complete": true,
  "vehicles": [
    {
      "external_id": "STOCK-4821",
      "make": "Volkswagen",
      "model": "Golf",
      "year": 2022,
      "asking_price": 24950,
      "fuel_type": "petrol",
      "mileage": 41200
    },
    {
      "external_id": "STOCK-4835",
      "make": "Audi",
      "model": "A4",
      "year": 2021,
      "asking_price": 28900,
      "fuel_type": "diesel",
      "body_type": "estate"
    }
  ]
}
  • All-or-nothing validation. The whole payload is validated first. One invalid vehicle rejects the call with 422 and a per-vehicle vehicles map; nothing is written.
  • complete: true declares the payload to be your entire stock. API-managed vehicles (those carrying one of your external ids) that are missing from it are unlisted, never deleted — they stay in your dashboard and come back if you send them again.
  • Empty protection. A complete sync with zero vehicles needs allow_empty: true, otherwise 409 empty_snapshot.
  • dry_run: true returns would_create, would_update, would_unlist and writes nothing.
  • Slots. Vehicles beyond your sale-slot allowance are saved unlisted with a sale_limit_reached warning instead of failing the sync.

Vehicles added by hand on the website are never touched by a sync.

Sale slots

Each workshop account has an allowance of vehicles that may be for sale at the same time (free tier, subscription tiers, or an amount assigned by Mi Taller). GET /v1/me returns slots.used, slots.limit and slots.available.

When every slot is taken, a car you put on sale is not refused: it waits in a queue (status queued, warning queued_for_slot) and goes on sale by itself, oldest first, as soon as a slot frees up - a car unlisted, sold or deleted, or more slots bought on {link}. Send queue_if_full: false to get the old 403 sale_limit_reached instead.

Putting many vehicles on sale

POST /v1/vehicles/publish takes a list of your vehicles in the order you want them listed. Free slots are filled first; the rest is queued in that order. The answer says which cars went on sale, which wait (with their place in the queue) and how many slots are missing. GET /v1/slots shows the same at any time: the cars for sale, the waiting list and slots_needed.

curl -X POST https://api.mitaller.us/v1/vehicles/publish \
  -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"vehicles": ["STOCK-4821", "STOCK-4822", "STOCK-4823"]}'
{
  "published": [{"uuid": "…", "external_id": "STOCK-4821"}],
  "queued": [{"uuid": "…", "external_id": "STOCK-4822", "position": 1},
             {"uuid": "…", "external_id": "STOCK-4823", "position": 2}],
  "already_published": [], "not_found": [],
  "slots": {"limit": 10, "used": 10, "available": 0, "queued": 2, "slots_needed": 2},
  "notice": {"code": "slots_needed", "slots_needed": 2, "buy_url": "https://mitaller.us/garage-owner/slots/purchase", "message": "…"}
}

While cars wait, the account owner is told how many extra slots are needed - in the platform, by e-mail and with the slots.needed webhook - again only when that number grows. POST /v1/vehicles/unpublish takes cars off sale or out of the queue; freed slots go straight to the next cars waiting (promoted_from_queue).

Two-way sync

The API also tells you what happens to your vehicles on the platform: sales, cars added or changed on the website or in the apps, and deletions. Pull the changes with the change feed, or have them pushed to you with webhooks - or both.

Change feed

GET /v1/vehicles?updated_since= returns every vehicle of yours changed after that moment, oldest change first, including sold and unlisted ones. Store the server_time of the answer and send it as updated_since next time. Deletions are listed by GET /v1/vehicles/deleted?since=.

curl "https://api.mitaller.us/v1/vehicles?updated_since=2026-09-28T08:00:00Z" \
  -H "Authorization: Bearer YOUR_API_KEY"
curl "https://api.mitaller.us/v1/vehicles/deleted?since=2026-09-28T08:00:00Z" \
  -H "Authorization: Bearer YOUR_API_KEY"

Sold status

A car sold through the platform comes back with status: "sold", sold_via: "platform" and sold_at - also when the seller marked it on the website. Report a sale from your side with {"sold": true}; putting the car back on sale clears the sale. status=sold lists them.

curl -X PATCH https://api.mitaller.us/v1/vehicles/STOCK-4821 \
  -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"sold": true, "sold_via": "elsewhere"}'

Webhooks

Register an https URL and we POST a JSON event to it for every change to your vehicles. The answer to the registration carries the secret used to sign every call - it is shown only once. Changes you made with your own API key are not sent back unless you set include_own_changes: true. events limits which events you receive.

curl -X POST https://api.mitaller.us/v1/webhooks \
  -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"url": "https://dms.example.com/hooks/marketplace"}'
EventMeaning
vehicle.createdA vehicle was added to your stock on the platform (website, app or another key).
vehicle.updatedDetails or photos changed.
vehicle.listedThe vehicle went on sale - can be the first time you see it.
vehicle.unlistedTaken off sale without a sale.
vehicle.soldSold - sold_via tells platform or elsewhere.
vehicle.deletedDeleted; data carries uuid and external_id only.
vehicle.queuedNo free slot: the vehicle waits in the queue.
slots.neededVehicles are waiting; data carries queued, slots_needed and buy_url.

Payload

{
  "id": "4127",
  "event": "vehicle.sold",
  "occurred_at": "2026-09-28T09:14:03.512Z",
  "source": "platform",
  "workshop": {
    "id": 90,
    "name": "Example Motors"
  },
  "data": {
    "vehicle": {
      "uuid": "…",
      "external_id": "STOCK-4821",
      "status": "sold",
      "sold_via": "platform",
      "sold_at": "2026-09-28T09:14:03Z",
      "make": "Volkswagen",
      "model": "Golf",
      "…": "…"
    }
  }
}

Verifying the signature

Every call carries X-Webhook-Event, X-Webhook-Id and X-Webhook-Signature: t=<unix time>,v1=<hex>, where v1 is the HMAC-SHA256 of t + "." + raw body with your secret. Reject calls whose t is more than 5 minutes old.

import hashlib, hmac

def verify(secret, header, raw_body):
    parts = dict(p.split("=", 1) for p in header.split(","))
    mac = hmac.new(secret.encode(), (parts["t"] + ".").encode() + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(mac, parts["v1"])

Answer with any 2xx within 10 seconds. Anything else is retried after 1 min, 5 min, 30 min, 2 h, 6 h and 12 h; after 50 failed deliveries in a row the webhook is switched off (PATCH {"is_active": true} turns it back on). Deliveries can arrive more than once or out of order: use id to skip duplicates and the vehicle's updated_at to keep the newest. vehicle.updated events are combined over 20 seconds.

Photos

Photos are ordered; order 0 is the main photo shown on listing cards. Large images are resized to a 2560 px long edge and re-encoded; anything above 15 MB after that is refused.

With the vehicle

Send image_urls in create/update. The photos are downloaded from your servers in the order given and replace the whole photo set. Omit the field to leave photos untouched. If none of the URLs can be fetched the existing photos are kept and a warning is returned.

One at a time

curl -X POST https://api.mitaller.us/v1/vehicles/STOCK-4821/images \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://cdn.example-dealer.be/stock/4821/rear.jpg", "order": 1}'
curl -X POST https://api.mitaller.us/v1/vehicles/STOCK-4821/images \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -F "image=@rear.jpg" -F "order=1"

Reorder

curl -X PUT https://api.mitaller.us/v1/vehicles/STOCK-4821/images/order \
  -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" \
  -d '{"ids": [912, 910, 911]}'
Remote URLs must be public http(s) addresses. Local, private and reserved network destinations are refused at every redirect hop. Content is checked to be a real image regardless of the Content-Type the host claims.

Equipment (106 values)

Send equipment as slugs in features, and parking aids in parking_assist. Only the values below are accepted; unknown slugs return 422 naming them. Omitting the field on PATCH keeps the equipment; sending [] clears it. Labels in every language: GET /v1/options.

Parking assist parking_assist

6
cam_360360° Camera
cam_frontFront camera
cam_rearRear camera
self_steeringSelf-steering systems
sens_frontFront parking sensors
sens_rearRear parking sensors

Exterior features 78

Electronics

10
absABS
espESP
immobiliserElectronic immobiliser
centralLockingCentral locking
keylessKeyless central locking
rainSensorRain sensor
lightSensorLight sensor
tyrePressureMonitorTyre pressure monitoring
startStopStart/stop system
electricTailgateElectric tailgate

Lighting

6
fogLightsFog lights
ledDrlLED daytime running lights
drlDaytime running lights
corneringLightCornering light
headlightWasherHeadlight washer
dynamicIndicatorsDynamic / sweeping / sliding indicators

Headlights

7
biXenonHeadlightsBi-xenon headlights
xenonHeadlightsXenon headlights
ledHeadlightsLED headlights
laserLightLaser light
highBeamAssistHigh beam assist
nightVisionNight vision assistant
matrixLightsIntelligent / matrix lights

Driving Assistants

12
distanceWarnerDistance warning
hillStartAssistHill start assist
speedLimiterSpeed limiter
emergencyBrakeAssistEmergency brake assist
laneAssistLane assist
blindSpotMonitorBlind spot monitor
tractionControlTraction control
trafficSignRecognitionTraffic sign recognition
adaptiveCorneringAdaptive cornering light
cruiseControlCruise control
adaptiveCruiseControlAdaptive cruise control
fatigueWarnerFatigue warning system

Comfort & Other

43
tintedWindowsTinted windows
adaptiveSuspensionAdaptive suspension
allWeatherTyresAll-weather tyres
heatedWindscreenHeated windscreen
disabledAccessDisabled access
roofRailsRoof rails
airSuspensionAir suspension
spareWheelSpare wheel
tyreSealantTyre sealant kit
fullSizeSpareFull-size spare wheel
powerSteeringPower steering
summerTyresSummer tyres
sportSuspensionSport suspension
sportPackageSport package
steelWheelsSteel wheels
alloyWheelsAlloy wheels
winterPackageWinter package
winterTyresWinter tyres
panoramicRoofPanoramic roof
slidingRoofSliding roof
foldingRoofFolding roof
towHitchTow hitch
alarmSystemAlarm system
ambientLightingAmbient lighting
electricWindowsElectric windows
handsFreeHands-free system
cargoPartitionCargo area partition
isofixIsofix
isofixPassengerIsofix passenger seat
emergencyCallSystemEmergency call system
smokersPackageSmoker's package
rightHandDriveRight-hand drive
skiStorageSki storage
auxiliaryHeatingAuxiliary heating
usbUSB
heatedSteeringWheelHeated steering wheel
leatherSteeringWheelLeather steering wheel
multifunctionSteeringWheelMultifunction steering wheel
paddleShiftersPaddle shifters
electricMirrorsElectric mirrors
electricFoldingMirrorsElectric folding mirrors
autoGlareFreeMirrorAuto-dimming interior mirror
virtualMirrorsVirtual side mirrors

Interior features 28

Infotainment

17
androidAutoAndroid Auto
appleCarplayApple CarPlay
bluetoothBluetooth
boardComputerOn-board computer
cdPlayerCD player
headUpDisplayHead-up display
inductiveChargingInductive charging for smartphones
musicStreamingIntegrated music streaming
navigationNavigation system
radioDabDAB radio
soundSystemSound system
touchscreenTouchscreen
tunerRadioTuner/Radio
tvTV
voiceControlVoice control
wifiHotspotWi-Fi hotspot
digitalInstrumentClusterFully digital instrument cluster

Seats

11
armrestArmrest
electricSeatAdjustElectric seat adjustment
electricSeatAdjustMemoryElectric seat adjustment with memory
electricSeatAdjustRearElectric rear seat adjustment
lumbarSupportLumbar support
massageSeatsMassage seats
seatVentilationSeat ventilation
seatHeatingSeat heating
seatHeatingRearRear seat heating
sportSeatsSport seats
foldablePassengerSeatFoldable passenger seat

Enumerations

Labels shown in the selected language; every language is in GET /v1/options. Unknown values are rejected rather than guessed.

vehicle_type

Carid 1Motorcycleid 2Truckid 3Vanid 4SUVid 5

year

1990 – 2027

fuel_type

12
ValueLabelEnglish
petrolPetrol / GasolinePetrol / Gasoline
dieselDieselDiesel
electricElectricElectric
hybrid_petrolHybrid (Petrol)Hybrid (Petrol)
hybrid_dieselHybrid (Diesel)Hybrid (Diesel)
phev_petrolPHEV (Petrol)PHEV (Petrol)
phev_dieselPHEV (Diesel)PHEV (Diesel)
lpgLPGLPG
cngCNGCNG
hydrogenHydrogenHydrogen
mild_hybridMild HybridMild Hybrid
otherOtherOther

gearbox_type

5
ValueLabelEnglish
manualManualManual
automaticAutomaticAutomatic
cvtCVTCVT
dctDual-Clutch (DCT)Dual-Clutch (DCT)
semi_autoSemi-automaticSemi-automatic

body_type

11
ValueLabelEnglish
sedanSedanSedan
hatchbackHatchbackHatchback
estateEstate / BreakEstate / Break
coupeCoupéCoupé
convertibleCabriolet / ConvertibleCabriolet / Convertible
suvSUVSUV
crossoverCrossoverCrossover
mpvMPV / MinivanMPV / Minivan
pickupPickupPickup
vanVanVan
otherOtherOther

drivetrain

3
ValueLabelEnglish
4wd4 wheel drive4 wheel drive
frontFront driveFront drive
rearRear driveRear drive

steering_position

2
ValueLabelEnglish
lhdLeft-hand driveLeft-hand drive
rhdRight-hand driveRight-hand drive

emission_standard

12
ValueLabelEnglish
euro0Euro 0Euro 0
euro1Euro 1Euro 1
euro2Euro 2Euro 2
euro3Euro 3Euro 3
euro4Euro 4Euro 4
euro5Euro 5Euro 5
euro6Euro 6Euro 6
euro6bEuro 6bEuro 6b
euro6cEuro 6cEuro 6c
euro6dEuro 6dEuro 6d
euro6d_tempEuro 6d-tempEuro 6d-temp
otherOtherOther

color

15

color is free text; these values are the ones the site translates.

ValueLabelEnglish
whiteWhiteWhite
blackBlackBlack
silverSilverSilver
grayGrayGray
blueBlueBlue
redRedRed
greenGreenGreen
yellowYellowYellow
orangeOrangeOrange
brownBrownBrown
beigeBeigeBeige
goldGoldGold
purplePurplePurple
pinkPinkPink
otherOtherOther

interior_material

6
ValueLabelEnglish
alcantaraAlcantaraAlcantara
fabricFabricFabric
artificial_leatherArtificial leatherArtificial leather
partial_leatherPartial leatherPartial leather
full_leatherFull leatherFull leather
velourVelourVelour

vehicle_condition

6
ValueLabelEnglish
factory_newFactory NewFactory New
new_conditionNew ConditionNew Condition
new_with_damageNew Condition with DamageNew Condition with Damage
usedUsedUsed
used_with_damageUsed with DamageUsed with Damage
partsUsed for PartsUsed for Parts

maintenance_history

4
ValueLabelEnglish
noneNoNo
dealershipYes, with dealershipYes, with dealership
platformYes, with the platformYes, with the platform
bothYes, with dealership and the platformYes, with dealership and the platform

airbags

4
ValueLabelEnglish
airbagDriverDriver airbagDriver airbag
airbagFrontFront airbagsFront airbags
airbagFrontSideFront & side airbagsFront & side airbags
airbagFullFront, side & rear airbagsFront, side & rear airbags

air_conditioning

5
ValueLabelEnglish
acNoneNoneNone
acManualManualManual
ac2Zone2-zone automatic2-zone automatic
ac3Zone3-zone automatic3-zone automatic
ac4Zone4-zone automatic4-zone automatic

Errors

Errors are JSON with a stable error code and a human message; some carry extra keys.

{
  "error": "validation_error",
  "message": "One or more fields are invalid.",
  "fields": {
    "fuel_type": [
      "\"gasoline\" is not a valid choice."
    ],
    "features": [
      "Unknown features: sunroof. GET /v1/options lists the accepted values."
    ]
  }
}
HTTPerrorMeaning
401invalid_api_keyMissing, unknown or revoked key.
403read_only_keyThe key may only read.
403workshop_blocked / workshop_inactiveThe workshop may not publish at the moment.
403sale_limit_reachedAll for-sale slots are in use. Body carries used, limit, available.
404vehicle_not_found / image_not_found / make_not_foundNot found within this workshop.
409duplicate_vin / duplicate_license_plateAnother vehicle already has that identifier.
409stale_updateThe stored external_updated_at is newer than the one sent.
409empty_snapshotA complete sync with no vehicles needs allow_empty: true.
422validation_errorField errors under `fields` (or `vehicles` for a sync). Nothing was written.
422image_url_* / image_too_large / image_unreadableA photo could not be fetched. On create/update these are warnings, not failures.
404webhook_not_foundNo webhook with that id for this workshop.
409webhook_limitAt most 5 webhooks per workshop.
422invalid_webhook_urlThe URL must be https and resolve to a public address.
429—Rate limit. Retry after the `Retry-After` header.

Successful responses: 200 read or update, 201 created, 204 deleted.

Rate limits

Each key may make 3 000 requests per hour. Above that the API answers 429 with a Retry-After header. A full nightly sync of a few hundred cars uses a handful of calls; if you need more, contact Mi Taller.

Photo downloads count against the same budget through the calls that trigger them, not per image.