# Market & demand

Understand the market for a car type in one country: how many are on sale, what they cost, how fast listings leave the market, how long that takes, whether the type moves faster or slower than the market as a whole, and how that has changed over the last 12 months. Field tables on this page are generated from the [OpenAPI contract](/openapi.yaml).

| Endpoint | MCP tool | Answers |
| --- | --- | --- |
| [`POST /v1/market`](#post-v1-market) | `get_market` | How big and how fast the market for a car type is |
| [`POST /v1/selling-times`](/docs/reference/valuations#post-v1-selling-times) | `forecast_selling_time` | How long one specific car takes to sell at each price level. See [selling-time forecasts](/docs/selling-time) |

Use both together: `POST /v1/market` for the type (a 2019 Volvo XC60 diesel automatic), then `POST /v1/selling-times` for the one car you are pricing.

## What the figures are

Every figure is an aggregate over the listings AutoUncle tracks in the requested market, never a single listing.

- **Listings, not registrations.** The counts describe the listings AutoUncle tracks, not every car registered or sold.
- **Left the market is not always a sale.** A listing that left the market was removed from sale, which is usually, but not always, a sale. Its price is the last asking price, not a transaction price.
- **The same segment as the similar-cars link.** The segment is the search behind a valuation's `similar_cars_url`, and `segment.similar_cars_url` opens it on the market's own AutoUncle site. It is make and model plus whatever you send that narrows it. A model year gives that year and one either side, kept within the model generation; in Germany and Italy it gives the exact year. Mileage narrows the segment only in Germany and Italy. Fuel, gearbox and body narrow it too.
- **Small numbers are withheld.** A figure built from fewer than 10 listings is left out, and `suppressed` says which block or month. Prices are rounded to three significant figures and mileage to 1,000 km or mi (100 Scandinavian mil), so no listing can be picked out.
- **Freshness.** On-sale and left-the-market figures can be up to three hours old, because they come from a shared cache. `as_of` says when the request read them.

| Block | What it says | Window |
| --- | --- | --- |
| `supply` | Listings on sale now: the count, asking price and mileage (5th percentile, median, 95th percentile), model years, the share in each price rating, the share whose price has been lowered and the most listed equipment variants | Now |
| `flow` | Listings that left the market per day, and listings that went on sale in the window and are still on sale, per day | Last 30 days |
| `turnover` | Median and mean days from going on sale to leaving the market | Last 60 days |
| `demand` | Days of supply, turnovers per year, and the level against the whole market | Now and the last 30 days |
| `trend` | Per month: listings that left the market, median days to leave and median last asking price | Last 12 complete months |

### Demand measures

- `days_of_supply` = listings on sale ÷ listings leaving the market per day. It is how long today's stock would last at the current pace.
- `turnovers_per_year` = 12 × listings that left in 30 days ÷ listings on sale.
- `relative_to_market` = the segment's `days_of_supply` ÷ the same measure for the market's whole used-car stock. Below 1 the type moves faster than the market.
- `level` is `high` when `relative_to_market` is below 0.8, `low` above 1.25, and `average` in between. Comparing with the market itself keeps the level meaningful across countries, and it cancels most of the effect of listings removed for reasons other than a sale.

`flow.new_listings_still_on_sale_per_day` counts only listings that are still on sale. A listing that went on sale and left within the window is not in it. So it is not total inflow, and subtracting `left_market_per_day` from it does not give a net change.

## Status and cost

| `status` | Means | Live cost |
| --- | --- | --- |
| `measured` | Figures were published | One credit |
| `partial` | A data store could not answer, so some blocks are null; `warnings` says which (`market_supply_unavailable`, `market_flow_unavailable`, `market_trend_unavailable`, `market_baseline_unavailable`) | Free; request it again |
| `insufficient_data` | Too few listings match, so every figure was withheld | Free |

Test keys return deterministic example figures (`synthetic: true`) for free. Nothing is stored: a replay with the same `Idempotency-Key` reads the market again without spending a credit, and there is no read-back endpoint. See [credits](/docs/credits).

## POST /v1/market

Market and demand figures for a car type.

Describes the market for a car type in one country: how many are on sale and at what prices and mileages, the price-rating mix, how fast listings arrive and leave the market, how long they take to leave, days of supply and a demand level relative to the whole market, and a 12-month trend of listings leaving the market. Send the same vehicle input as a valuation; at least a make and model must be recognised, and model year, mileage, fuel, gearbox and body narrow the segment exactly as the valuation's similar_cars_url does. Every figure is an aggregate over the listings AutoUncle tracks in that market (not registrations or confirmed sales); left the market means removed from sale. A figure built from fewer than 10 listings is withheld and listed in suppressed. One credit for a measured live result; partial and insufficient_data results, refusals, failures, idempotent replays and test keys are free. Needs the valuations:write scope and shares the valuation rate and concurrency limits. Nothing is stored: a replay with the same Idempotency-Key reads the market again without spending a credit.

Nothing is stored: a replay with the same Idempotency-Key reads the market again without spending a credit, and there is no read-back endpoint. Counts against the valuation rate limit and needs a valuation concurrency slot, like POST /v1/valuations.

- **Scope:** `valuations:write`
- **Cost:** One credit for a `measured` live result. `partial` and `insufficient_data` results, test keys, refusals, failures and idempotent replays are free.
- **Rate limit:** valuations bucket, default 60 requests per minute. See [limits](/docs/concepts/limits).

### Parameters

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `Idempotency-Key` | header | string | No | Workspace- and mode-scoped retry key. A replay of a finished request spends no credit. 1 to 200 characters. |

### Request body

`application/json`, a `MarketRequest`: A car type in one market: the same vehicle input as a valuation (a VehicleInput, a description or photos), of which at least a make and model must be recognised. Mileage and model year are optional and only narrow the segment as the similar-cars link does. Pricing does not apply. Unknown fields are rejected.

| Field | Type | Description |
| --- | --- | --- |
| `country` **required** | string | Market as an ISO 3166-1 alpha-2 code, such as DK, DE or GB. Every figure comes from that market's own listings only. 2 to 10 characters. |
| `vehicle` | [VehicleInput](/docs/reference/vehicles#vehicleinput-describing-a-vehicle) | The vehicle, as a VehicleInput: an AVS vehicle document (any `vehicle` an endpoint returned, posted back unchanged) or the vehicle's attributes as a listing gives them. |
| `description` | string | Unstructured listing text describing the vehicle. Existing parsers and deployment-configured optional AI can propose attributes; the response identifies assumptions and unresolved inputs. 1 to 20000 characters. |
| `images` | array | Up to eight vehicle photos, each supplied by HTTPS URL or inline base64 data, to identify the car type. AI image resolution is deployment-configured and never runs for test keys. Photos cost nothing extra on a market request. At most 8 items. |
| `images[].url` | string (uri) | Public HTTPS image URL on port 443, without credentials or fragments. Private network destinations and redirects are rejected. Remote images must be supported image types and at most 8 MB each. At most 2048 characters. |
| `images[].data` | string | Strict base64-encoded image bytes, without a data-URL prefix. Inline data must also fit the total 1 MB API request limit. At most 1000000 characters. |
| `images[].media_type` | string | MIME type for inline image bytes: image/jpeg, image/png, image/webp or image/gif. The actual image signature is checked. At most 100 characters. |
| `options` | object | How the vehicle is resolved. |
| `options.resolution` | string | auto uses deterministic resolution and optional configured AI; no_ai and strict use deterministic resolution only. One of `auto`, `no_ai`, `strict`. |

Structured example:

```json
{
  "country": "SE",
  "vehicle": {
    "make": "Volvo",
    "model": "XC60",
    "model_year": 2019,
    "fuel": "diesel",
    "transmission": "automatic"
  }
}
```

Text example:

```json
{
  "country": "DE",
  "description": "VW Golf 1.5 TSI 2020"
}
```

### Response

`application/json`, a `MarketResponse`: Market & demand figures for a car type in one market: aggregates over the listings AutoUncle tracks there, never a listing. Errors return a [Problem](/docs/reference/valuations#the-problem-object) as `application/problem+json`.

| Field | Type | Description |
| --- | --- | --- |
| `request_id` | string | The request's ID, shown in the console request log. Pattern `^mkt_[A-Za-z0-9]+$`. |
| `object` | string | Always `market`. One of `market`. |
| `status` | string | measured: figures were published; one credit on a live key. partial: a data store could not answer, so some figures are missing (see warnings); not charged. insufficient_data: every figure was withheld because too few listings match; not charged. One of `measured`, `partial`, `insufficient_data`. |
| `country` | string | Market as an ISO 3166-1 alpha-2 code, normalized from your request (for example `SE`). Pattern `^[A-Z]{2}$`. |
| `mode` | string | `test` for a test key (synthetic figures) or `live` for a live key. One of `live`, `test`. |
| `synthetic` | boolean | True for test keys: deterministic example figures, no market data. |
| `vehicle` | [Vehicle](/docs/reference/vehicles#the-vehicle-object) | The identified vehicle. An AVS vehicle document; left out when the vehicle could not be identified to a brand and a model, with the reason in `identification`. |
| `identification` | [VehicleIdentification](/docs/reference/vehicles#identification) | How the vehicle was identified: status, depth, candidates and the provenance of every value in `vehicle`. |
| `segment` | object | The listings the figures describe. |
| `segment.criteria` **required** | object | What a listing must match to be in the segment, in the public vocabulary. Null means not restricted. |
| `segment.criteria.make` **required** | string | Make every listing in the segment has. |
| `segment.criteria.model` **required** | string | Model every listing in the segment has. |
| `segment.criteria.model_year` **required** | object or null | Model years the segment covers. Null when not restricted. |
| `segment.criteria.model_year.from` **required** | integer or null | Earliest model year. |
| `segment.criteria.model_year.to` **required** | integer or null | Latest model year. |
| `segment.criteria.mileage` **required** | object or null | Mileage band the segment covers (Germany and Italy only, when you send a mileage). Null when not restricted. |
| `segment.criteria.mileage.from` **required** | integer or null | Lowest mileage. |
| `segment.criteria.mileage.to` **required** | integer or null | Highest mileage. |
| `segment.criteria.mileage.unit` **required** | string | `km`, `mi` or `mil` (Scandinavian mil). One of `km`, `mi`, `mil`. |
| `segment.criteria.fuel` **required** | string or null | Fuel every listing has. Null when not restricted. |
| `segment.criteria.transmission` **required** | string or null | `automatic` or `manual` when the gearbox is restricted, otherwise null. One of `automatic`, `manual`. |
| `segment.criteria.body` **required** | string or null | Body type every listing has. Null when not restricted. |
| `segment.criteria.engine_size_l` **required** | number or null | Engine size in litres every listing has. Null when not restricted. |
| `segment.similar_cars_url` **required** | string or null (uri) | The same segment as a search on the market's own AutoUncle site. |
| `as_of` | string (date-time) | When the figures were read. On-sale and left-the-market figures can be up to three hours old (shared cache). |
| `supply` | object or null | Listings on sale now. Null when those figures could not be read (market_supply_unavailable warning). |
| `supply.on_sale` **required** | integer or null | Listings on sale now in the segment. Null when fewer than 10, with on_sale_band set. Minimum 0. |
| `supply.on_sale_band` **required** | string or null | fewer_than_10 when the count is withheld; every other supply figure is then left out. One of `fewer_than_10`. |
| `supply.price` | object | Asking prices of the listings on sale. |
| `supply.price.p5` **required** | integer or null | 5th percentile asking price, rounded to three significant figures. Minimum 0. |
| `supply.price.median` **required** | integer or null | Median asking price, rounded to three significant figures. Minimum 0. |
| `supply.price.p95` **required** | integer or null | 95th percentile asking price, rounded to three significant figures. Minimum 0. |
| `supply.price.currency` **required** | string | ISO 4217 currency of the market. Pattern `^[A-Z]{3}$`. |
| `supply.mileage` | object | Mileage of the listings on sale, in the market's unit. |
| `supply.mileage.p5` **required** | integer or null | 5th percentile mileage, rounded to 1,000 km or mi (100 Scandinavian mil). Minimum 0. |
| `supply.mileage.median` **required** | integer or null | Median mileage, rounded the same way. Minimum 0. |
| `supply.mileage.p95` **required** | integer or null | 95th percentile mileage, rounded the same way. Minimum 0. |
| `supply.mileage.unit` **required** | string | `km`, `mi` or `mil` (Scandinavian mil): the market's unit. One of `km`, `mi`, `mil`. |
| `supply.model_years` | object or null | Model years of the listings on sale. Null when the store returned none. |
| `supply.model_years.most_common` **required** | integer or null | The most listed model year. Minimum 1900. |
| `supply.model_years.from` **required** | integer or null | Earliest model year of all but the outer 2% of listings. Minimum 1900. |
| `supply.model_years.to` **required** | integer or null | Latest model year of all but the outer 2% of listings. Minimum 1900. |
| `supply.price_ratings` | object | Share of listings on sale in each AutoUncle price rating (5 is super price, 1 is expensive), to two decimals. |
| `supply.price_ratings.5` **required** | number or null | Share of listings on sale with price rating 5. 0 to 1. |
| `supply.price_ratings.4` **required** | number or null | Share of listings on sale with price rating 4. 0 to 1. |
| `supply.price_ratings.3` **required** | number or null | Share of listings on sale with price rating 3. 0 to 1. |
| `supply.price_ratings.2` **required** | number or null | Share of listings on sale with price rating 2. 0 to 1. |
| `supply.price_ratings.1` **required** | number or null | Share of listings on sale with price rating 1. 0 to 1. |
| `supply.price_ratings.unrated` **required** | number or null | Share of listings on sale without a price rating. 0 to 1. |
| `supply.share_with_price_drop` | number or null | Share of listings on sale whose asking price has been lowered. 0 to 1. |
| `supply.top_equipment_variants` | array | The three most listed equipment-variant names, most listed first. At most 3 items. |
| `flow` | object or null | Pace over the last 30 days. Null when withheld (fewer than 10 listings left the market in the window) or unavailable. |
| `flow.window_days` **required** | integer | Days the per-day rates are averaged over. Always 30. |
| `flow.left_market_per_day` **required** | number or null | Listings that left the market per day over the window (on sale at least one day). Left the market means removed from sale, usually but not always a sale. Minimum 0. |
| `flow.new_listings_still_on_sale_per_day` **required** | number or null | Listings that went on sale within the window and are still on sale, per day. Listings that came and went within the window are not counted, so this is not total inflow. Minimum 0. |
| `turnover` | object or null | How long listings of this type take to leave the market. Null when withheld or unavailable. |
| `turnover.window_days` **required** | integer | Days back the listings that left the market are taken from. Always 60. |
| `turnover.median_days_to_leave` **required** | integer or null | Median days from going on sale to leaving the market, for listings that left in the window. Minimum 0. |
| `turnover.mean_days_to_leave` **required** | integer or null | Mean of the same. Minimum 0. |
| `demand` | object or null | Derived demand measures. Null when on_sale or flow is withheld or unavailable. |
| `demand.days_of_supply` **required** | integer or null | Listings on sale ÷ listings leaving the market per day: how long today's stock lasts at the current pace. Minimum 0. |
| `demand.turnovers_per_year` **required** | number or null | 12 × listings that left in 30 days ÷ listings on sale. Minimum 0. |
| `demand.relative_to_market` **required** | number or null | days_of_supply ÷ the same measure for the market's whole used-car stock. Below 1 the type moves faster than the market. Minimum 0. |
| `demand.level` **required** | string or null | high below 0.8 relative_to_market, low above 1.25, otherwise average. Null when the whole market's figures could not be read. One of `high`, `average`, `low`. |
| `trend` | object or null | The last 12 complete months of listings that left the market. Null when it could not be read (market_trend_unavailable warning). |
| `trend.months` **required** | integer | Complete calendar months in series: 12, or fewer where the store holds less history. 0 to 12. |
| `trend.currency` **required** | string | ISO 4217 currency of `median_last_asking_price`. Pattern `^[A-Z]{3}$`. |
| `trend.series` **required** | array | Oldest month first. At most 12 items. |
| `trend.series[].month` **required** | string | Calendar month as `YYYY-MM`. Pattern `^[0-9]{4}-[0-9]{2}$`. |
| `trend.series[].left_market` **required** | integer or null | Listings that left the market that month (on sale at least one day). Minimum 0. |
| `trend.series[].median_days_to_leave` **required** | integer or null | Median days from going on sale to leaving the market. Minimum 0. |
| `trend.series[].median_last_asking_price` **required** | integer or null | Median last asking price before leaving the market, rounded to three significant figures. Not a transaction price. Minimum 0. |
| `trend.series[].suppressed` **required** | boolean | True when fewer than 10 listings left the market that month; its figures are then null. |
| `trend.current_month` **required** | object | The month in progress, which is never in series. |
| `trend.current_month.month` **required** | string | The month in progress, as `YYYY-MM`. Pattern `^[0-9]{4}-[0-9]{2}$`. |
| `trend.current_month.partial` **required** | boolean | Always `true`: the month in progress is never in `series`. |
| `suppressed` | array | Every block or trend month withheld because it would be built from fewer than 10 listings. |
| `suppressed[].section` **required** | string | `supply`, `flow`, `turnover`, `demand` or `trend`. One of `supply`, `flow`, `turnover`, `demand`, `trend`. |
| `suppressed[].month` | string | For `trend`, the month withheld, as `YYYY-MM`. Pattern `^[0-9]{4}-[0-9]{2}$`. |
| `suppressed[].reason` **required** | string | Why it was withheld. Always `fewer_than_10_listings`. One of `fewer_than_10_listings`. |
| `warnings` | array | Problems with this request, for example `market_flow_unavailable` (status `partial`) or `model_not_recognized`. Match on `code`. |
| `warnings[].code` **required** | string | Stable machine-readable warning code. Pattern `^[a-z][a-z0-9_]*$`. |
| `warnings[].message` **required** | string | Plain-language explanation. |
| `usage` | object | Billing for this call. |
| `usage.billable` **required** | boolean | `true` when this result captured a credit (status `measured` on a live key). |
| `usage.credits_used` **required** | integer | Credits this call consumed. Always 0 on an idempotent replay. 0 to 1. |
| `usage.original_credits_used` **required** | integer | Credits the original request consumed (0 or 1), also on a replay. 0 to 1. |
| `usage.charges` **required** | object | What `original_credits_used` paid for. Empty when nothing was charged. |
| `usage.charges.base` | integer | The market figures, 1 credit. Minimum 1. |
| `usage.credits_remaining` **required** | integer | Workspace credits left after this call. Minimum 0. |
| `usage.cache_hit` **required** | boolean | Reserved. Always false in this version. |
| `usage.idempotent_replay` **required** | boolean | `true` when the same Idempotency-Key and body were sent before; the market is read again for free. |
| `usage.mode` **required** | string | `test` or `live`. One of `live`, `test`. |
| `notes` | [Note](/docs/notices#notes) array | Standing limitations and notices, including `market_figures_describe_listings`. Always present. |
| `attributions` | [Attribution](/docs/notices#attributions) array | Data sources that contributed to this result. Always present. |

### Response headers

| Header | Description |
| --- | --- |
| `X-Request-Id` | The HTTP request ID, on every response. Use it to correlate one HTTP exchange in proxy and application logs; it echoes a valid X-Request-Id you send. It is not the valuation ID. |
| `Retry-After` | Seconds to wait before retrying. |

### Errors

| Code | HTTP | Retryable | Meaning |
| --- | --- | --- | --- |
| [`invalid_request`](/docs/errors#invalid_request) | 400 | No | Send a request matching the documented schema. |
| [`country_required`](/docs/errors#country_required) | 400 | No | Include country, the valuation market, in the request. |
| [`unsupported_country`](/docs/errors#unsupported_country) | 400 | No | Choose a supported ISO country code. |
| [`unauthenticated`](/docs/errors#unauthenticated) | 401 | No | Supply an API key as a Bearer token. |
| [`invalid_api_key`](/docs/errors#invalid_api_key) | 401 | No | Supply a valid AutoUncle Data Services API key. |
| [`key_revoked`](/docs/errors#key_revoked) | 401 | No | This key has expired or been revoked. Create a new key. |
| [`insufficient_credits`](/docs/errors#insufficient_credits) | 402 | No | The organization has no credits available. Contact sales for a package. |
| [`key_spend_limit_reached`](/docs/errors#key_spend_limit_reached) | 402 | No | This API key has reached its monthly credit limit. |
| [`insufficient_scope`](/docs/errors#insufficient_scope) | 403 | No | Use a key with the required scope. |
| [`country_not_enabled`](/docs/errors#country_not_enabled) | 403 | No | This country is not enabled for this organization or key. |
| [`organization_pending`](/docs/errors#organization_pending) | 403 | No | This workspace is waiting for AutoUncle to approve it. |
| [`organization_suspended`](/docs/errors#organization_suspended) | 403 | No | This organization is inactive. Contact support. |
| [`unknown_catalogue_id`](/docs/errors#unknown_catalogue_id) | 404 | No | The catalogue ID is unknown. Fetch current IDs from the catalogue API. |
| [`idempotency_conflict`](/docs/errors#idempotency_conflict) | 409 | No | This idempotency key was used with different input. Choose a new key. |
| [`request_in_progress`](/docs/errors#request_in_progress) | 409 | Yes | A request with this idempotency key is still running. Retry later with the same key. |
| [`payload_too_large`](/docs/errors#payload_too_large) | 413 | No | The request exceeds the maximum supported size of 1 MB. |
| [`vehicle_not_identified`](/docs/errors#vehicle_not_identified) | 422 | No | Provide more vehicle attributes or select catalogue IDs. |
| [`catalogue_id_conflict`](/docs/errors#catalogue_id_conflict) | 422 | No | The catalogue IDs do not describe the same vehicle hierarchy. |
| [`vehicle_out_of_range`](/docs/errors#vehicle_out_of_range) | 422 | No | The vehicle is outside the supported valuation range. |
| [`images_unreadable`](/docs/errors#images_unreadable) | 422 | No | Provide readable supported images. |
| [`rate_limited`](/docs/errors#rate_limited) | 429 | Yes | The request rate limit was reached. Retry after the current minute. |
| [`test_limit_reached`](/docs/errors#test_limit_reached) | 429 | Yes | This workspace has used its fair-use allowance of test-key requests for now. |
| [`concurrency_limited`](/docs/errors#concurrency_limited) | 429 | Yes | Too many valuations are running at the same time for this organization. |
| [`rate_limit_unavailable`](/docs/errors#rate_limit_unavailable) | 503 | Yes | Request limiting is temporarily unavailable. Retry later. |
| [`engine_busy`](/docs/errors#engine_busy) | 503 | Yes | The valuation engine is at capacity. Retry after a short delay. |
| [`request_timeout`](/docs/errors#request_timeout) | 504 | Yes | The valuation request exhausted its processing time budget. |
| [`resolution_timeout`](/docs/errors#resolution_timeout) | 504 | Yes | Vehicle interpretation did not finish within its time budget. |
| [`resolution_unavailable`](/docs/errors#resolution_unavailable) | 503 | Yes | Vehicle interpretation is temporarily unavailable. |
| [`resolution_invalid_response`](/docs/errors#resolution_invalid_response) | 502 | Yes | Vehicle interpretation returned an invalid response. |
| [`image_timeout`](/docs/errors#image_timeout) | 504 | Yes | Image retrieval did not finish within its time budget. |
| [`image_unavailable`](/docs/errors#image_unavailable) | 503 | Yes | The image service is temporarily unavailable. |
| [`image_invalid_response`](/docs/errors#image_invalid_response) | 502 | Yes | The image service returned an invalid response. |
| [`market_data_unavailable`](/docs/errors#market_data_unavailable) | 503 | Yes | Market figures are temporarily unavailable. |
| [`internal_error`](/docs/errors#internal_error) | 500 | No | The valuation could not be completed. Contact support with the request ID. |

### Examples

**curl**

```bash
curl https://data-services.autouncle.com/v1/market \
  -H "Authorization: Bearer $AUTOUNCLE_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: market-001' \
  -d @- <<'JSON'
{
  "country": "SE",
  "vehicle": {
    "make": "Volvo",
    "model": "XC60",
    "model_year": 2019,
    "fuel": "diesel",
    "transmission": "automatic"
  }
}
JSON
```

**Ruby**

```ruby
require "json"
require "net/http"

uri = URI("https://data-services.autouncle.com/v1/market")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch("AUTOUNCLE_API_KEY")}"
request["Content-Type"] = "application/json"
request["Idempotency-Key"] = "market-001"
request.body = JSON.generate({
  "country" => "SE",
  "vehicle" => {
    "make" => "Volvo",
    "model" => "XC60",
    "model_year" => 2019,
    "fuel" => "diesel",
    "transmission" => "automatic"
  }
})
response = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(request) }
puts JSON.pretty_generate(JSON.parse(response.body))
```

**Python**

```python
import json
import os

import requests

response = requests.post(
    "https://data-services.autouncle.com/v1/market",
    headers={
        "Authorization": f"Bearer {os.environ['AUTOUNCLE_API_KEY']}",
        "Idempotency-Key": "market-001",
    },
    json={
        "country": "SE",
        "vehicle": {
            "make": "Volvo",
            "model": "XC60",
            "model_year": 2019,
            "fuel": "diesel",
            "transmission": "automatic"
        }
    },
    timeout=30,
)
print(json.dumps(response.json(), indent=2))
```

**JavaScript**

```javascript
const response = await fetch("https://data-services.autouncle.com/v1/market", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.AUTOUNCLE_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": "market-001",
  },
  body: JSON.stringify({
    country: "SE",
    vehicle: {
      make: "Volvo",
      model: "XC60",
      model_year: 2019,
      fuel: "diesel",
      transmission: "automatic"
    }
  }),
});
console.log(JSON.stringify(await response.json(), null, 2));
```
