Skip to content

For business

Data API documentation

Everything you need to call the GCC Car Deals Data API: authentication, the endpoints with their parameters and responses, errors and limits.

Quick start

Subscribe to get an API key, keep it in an environment variable and send it as a Bearer token. This request asks for the market value of a Toyota Camry today.

Base URL: https://gcccardeals.com/api/b2b/v1

curl -s "https://gcccardeals.com/api/b2b/v1/valuation?make=Toyota&model=Camry&year=2019&km=90000" \
  -H "Authorization: Bearer $GCC_API_KEY"

Authentication

Send your API key in the Authorization header as a Bearer token, or in the X-API-Key header. Never put it in a URL: URLs are logged. Keys are confidential and issued per market, so a key for one market cannot query another. Starter and Dataset include a key for the market you choose; Pro and Business include a key for each market. You create your keys in your Data API dashboard, and the full key is shown only once.

Valuation

Available on every plan

GET https://gcccardeals.com/api/b2b/v1/valuation

The market value of one car on a date: our estimate from comparable ads, each adjusted to the car's model year and mileage, with the typical error and range of such estimates and the ads behind it.

Parameters

Valuation: Parameters
ParameterRequiredDescription
makeYesThe make as you would write it, for example Toyota. Names and common spellings are recognised.
modelYesThe model, for example Camry.
yearYesThe model year, from 1950 to next year.
trimNoThe trim as written on the car, for example GXR. It narrows the comparison and never changes the car.
kmNoThe odometer reading in kilometres. When given, the value follows the car's mileage.
as_ofNoThe date to value the car on, as YYYY-MM-DD in UTC. Defaults to today. It must fall between the start of the market's price history and today, and within your plan's history window.
conditionNoused (the default) or new.
window_daysNoHow many days back to look for comparable cars, counted from the valuation date (from today for the price table), from 30 to 180. Default 90.
comparablesNoHow many comparable ads to return as evidence, from 0 to 25. Default 10.
marketNoOptional. It must match the market of your key; a mismatch is an error.

Example request

curl -s "https://gcccardeals.com/api/b2b/v1/valuation?make=Toyota&model=Camry&year=2019&km=90000" \
  -H "Authorization: Bearer $GCC_API_KEY"

Example response

Illustrative values, shown to explain the format. They are not current prices, and the ad is an example.

{
  "version": 1,
  "method": "adjusted-comparables-v2",
  "market": "ae",
  "currency": "AED",
  "as_of": "2026-09-15",
  "window_days": 90,
  "history_since": "2026-06-12",
  "subject": {
    "make": "toyota",
    "model": "camry",
    "model_year": 2019,
    "trim": null,
    "trim_label": null,
    "km": 90000,
    "condition": "used"
  },
  "valuation": {
    "value": 52000,
    "low": 47500,
    "high": 56000,
    "confidence": "high",
    "indicative": false,
    "typical_error_pct": 8.1,
    "range_low": 43900,
    "range_high": 61000,
    "basis": "model_year",
    "premium_trim_group": null,
    "mileage_matched": true
  },
  "counts": {
    "candidates_total": 31,
    "truncated": false,
    "candidates": 31,
    "distinct_cars": 27,
    "outliers_dropped": 1,
    "pool": 26,
    "used": 26,
    "same_trim": 0,
    "same_year": 22
  },
  "year_counts": {
    "2018": 4,
    "2019": 22
  },
  "pool": {
    "median_price": 53000,
    "p25": 48000,
    "p75": 57000,
    "median_km": 96000,
    "sources": 4
  },
  "comparables": [
    {
      "source": "Example marketplace",
      "url": "https://www.example.com/listing/12345",
      "model_year": 2019,
      "trim": null,
      "km": 88000,
      "asking_price": 51500,
      "price_date": "2026-09-10",
      "adjusted_price": 51400,
      "first_seen": "2026-08-30",
      "last_seen": "2026-09-16",
      "still_listed": true,
      "listed_on_as_of": true,
      "city": "riyadh"
    }
  ],
  "reason": null,
  "quota": {
    "monthly": 3000,
    "used_month": 12,
    "daily": null,
    "used_today": null
  },
  "notes": [
    "Prices are asking prices from the listings we observe, not transaction prices."
  ]
}

Response fields

version
The response format version. Within a version, fields are added and never removed or renamed.
method
The name and version of the method that produced the answer.
market
The market the answer is for: qa, ae or sa.
currency
The currency of every price in the answer.
as_of
The date the answer is for, as a UTC date.
window_days
How many days back from as_of the comparable cars were taken from.
history_since
The first date this market has price history for.
subject
The car as we understood it: make, model, model_year, trim, trim_label, km and condition.
valuation.value
The market value: our estimate of the car's market asking price on as_of, made from comparable ads, each adjusted to the car's model year and mileage. Null when no comparable car is found; reason says why.
valuation.low
The lower end of the range in which the middle half of the comparable cars' adjusted prices fall.
valuation.high
The upper end of that range.
valuation.confidence
How much evidence stands behind the value: high, medium or low.
valuation.indicative
True when there is very little evidence behind the value, which makes it a rough guide; its confidence is low then. Otherwise false.
valuation.typical_error_pct
How close values like this come to individual cars' asking prices, measured on our own data: half of such cars ask within this many percent of the value. Null when it has not been measured.
valuation.range_low
The lower end of the range most cars like this ask within, measured on our own data. Null when typical_error_pct is null.
valuation.range_high
The upper end of that range.
valuation.basis
What the value mainly rests on: trim (cars stating your trim), trim_group (cars of your price-moving trim group), model_year (cars of your car's model year) or adjusted_years (too few cars of your car's model year, so cars of nearby model years adjusted to it).
valuation.premium_trim_group
The price-moving trim group the car was valued against, when its trim belongs to one.
valuation.mileage_matched
True when the value follows your car's mileage: you gave km and the comparable ads state theirs.
counts.candidates_total
All matching ads we observed in the window.
counts.truncated
True when candidates_total is larger than the number of ads read.
counts.candidates
The ads read for this valuation.
counts.distinct_cars
The number of separate cars behind those ads; a car advertised more than once counts once.
counts.outliers_dropped
Cars set aside because their price is unusual for this comparison.
counts.pool
The cars left in the comparison after that.
counts.used
The cars the value was taken from.
counts.same_trim
How many cars of your car's model year share the trim you gave.
counts.same_year
How many of the cars used are of your car's model year.
year_counts
How many comparable cars there are per model year, which shows which model years the value draws on.
pool.median_price
The median asking price across the whole comparison set.
pool.p25
The lower end of the middle half of that set's asking prices.
pool.p75
The upper end of the middle half of that set's asking prices.
pool.median_km
The median mileage of the set, in kilometres.
pool.sources
How many marketplaces the set comes from.
comparables[].source
The marketplace the ad was found on.
comparables[].url
A link to the original ad, or null in the few cases where we withhold it for privacy.
comparables[].model_year
The ad's model year.
comparables[].trim
The ad's trim, when it states one.
comparables[].km
The ad's odometer reading in kilometres, when it states one.
comparables[].asking_price
The ad's asking price on price_date, in the market's currency.
comparables[].price_date
The date of the asking price used.
comparables[].adjusted_price
The ad's asking price moved to your car's model year and mileage. It is what this ad contributes to the value.
comparables[].first_seen
The date we first saw the ad.
comparables[].last_seen
The date we last saw the ad.
comparables[].still_listed
Whether the ad is still listed today.
comparables[].listed_on_as_of
Whether the ad was listed on the as_of date itself.
comparables[].city
The city the ad gives, when it gives one.
reason
When no value could be given, a plain-language reason. Otherwise null.
quota
Your quota and how much of it you have used: monthly, used_month, daily and used_today.
notes
Plain-language notes on how to read the numbers.

Market prices

Available on every plan

GET https://gcccardeals.com/api/b2b/v1/market-prices

The typical asking price and its range for one make and model, by model year, trim family and mileage band, plus our estimate of the price for each group, including groups too small to price.

Parameters

Market prices: Parameters
ParameterRequiredDescription
makeYesThe make as you would write it, for example Toyota. Names and common spellings are recognised.
modelYesThe model, for example Camry.
conditionNoused (the default) or new.
window_daysNoHow many days back to look for comparable cars, counted from the valuation date (from today for the price table), from 30 to 180. Default 90.
marketNoOptional. It must match the market of your key; a mismatch is an error.

Example request

curl -s "https://gcccardeals.com/api/b2b/v1/market-prices?make=Toyota&model=Camry" \
  -H "Authorization: Bearer $GCC_API_KEY"

Example response

Illustrative values, shown to explain the format. They are not current prices, and the ad is an example.

{
  "version": 1,
  "method": "market-prices-v1",
  "market": "ae",
  "currency": "AED",
  "as_of": "2026-09-29",
  "window_days": 90,
  "history_since": "2026-06-12",
  "make": "toyota",
  "model": "camry",
  "condition": "used",
  "cells": [
    {
      "model_year": 2019,
      "trim_family": "base",
      "mileage_band": "100-150k",
      "cars": 12,
      "median_price": 52000,
      "p25_price": 48000,
      "p75_price": 56000,
      "median_km": 128000,
      "estimated_price": 52300,
      "estimate_range_low": 44100,
      "estimate_range_high": 61400,
      "estimate_error_pct": 8.1,
      "estimate_confidence": "high"
    }
  ],
  "quota": {
    "monthly": 3000,
    "used_month": 12,
    "daily": null,
    "used_today": null
  },
  "notes": [
    "Prices are asking prices from the listings we observe, not transaction prices."
  ]
}

Response fields

version
The response format version. Within a version, fields are added and never removed or renamed.
method
The name and version of the method that produced the answer.
market
The market the answer is for: qa, ae or sa.
currency
The currency of every price in the answer.
as_of
The date the answer is for, as a UTC date.
window_days
How many days back from as_of the comparable cars were taken from.
history_since
The first date this market has price history for.
make
The make as we list it.
model
The model as we list it.
condition
used or new.
cells
The price table for this make and model: one entry per model year, trim family and mileage band.
cells[].model_year
The model year.
cells[].trim_family
The trim family: the name of a price-moving trim, or base for the base trims.
cells[].mileage_band
The mileage band the cars fall in.
cells[].cars
The number of separate cars in the group.
cells[].median_price
The typical asking price of the group. Null for a group too small to price.
cells[].p25_price
The lower end of the middle half of asking prices, or null.
cells[].p75_price
The upper end of the middle half of asking prices, or null.
cells[].median_km
The median mileage of the group, in kilometres.
cells[].estimated_price
Our estimate of the asking price of the group. Unlike the typical price, it is also given for a group too small to price. Null when we have no estimate for it.
cells[].estimate_range_low
The lower end of the range most cars like this ask within, measured on our own data. Null when it has not been measured.
cells[].estimate_range_high
The upper end of that range.
cells[].estimate_error_pct
How close estimates like this come to individual cars' asking prices, measured on our own data: half of such cars ask within this many percent of the estimate. Null when it has not been measured.
cells[].estimate_confidence
How much evidence the estimate rests on: high, medium, low or indicative (very little evidence).
quota
Your quota and how much of it you have used: monthly, used_month, daily and used_today.
notes
Plain-language notes on how to read the numbers.

Full market table (CSV)

Pro, Business and Dataset

GET https://gcccardeals.com/api/b2b/v1/market-prices.csv

The whole market's price table, with our estimate for each group, as one CSV file, refreshed every day. A download counts as one call.

Parameters

Full market table (CSV): Parameters
ParameterRequiredDescription
marketNoOptional. It must match the market of your key; a mismatch is an error.

Example request

curl -s "https://gcccardeals.com/api/b2b/v1/market-prices.csv" \
  -H "Authorization: Bearer $GCC_API_KEY" \
  -o market-prices.csv

The file is streamed. If the connection breaks before the end, discard it: the X-Total-Rows header tells you how many rows to expect.

Columns

make
The make as we list it.
model
The model as we list it.
model_year
The model year.
trim_family
The trim family: the name of a price-moving trim, or base for the base trims.
condition
used or new.
mileage_band
The mileage band the cars fall in.
cars
The number of separate cars in the group.
median_price
The typical asking price of the group. Null for a group too small to price.
p25_price
The lower end of the middle half of asking prices, or null.
p75_price
The upper end of the middle half of asking prices, or null.
median_km
The median mileage of the group, in kilometres.
currency
The currency of every price in the answer.
computed_on
The date the table or file was computed, as a UTC date.
estimated_price
Our estimate of the asking price of the group. Unlike the typical price, it is also given for a group too small to price. Null when we have no estimate for it.
estimate_range_low
The lower end of the range most cars like this ask within, measured on our own data. Null when it has not been measured.
estimate_range_high
The upper end of that range.
estimate_error_pct
How close estimates like this come to individual cars' asking prices, measured on our own data: half of such cars ask within this many percent of the estimate. Null when it has not been measured.
estimate_confidence
How much evidence the estimate rests on: high, medium, low or indicative (very little evidence).

Listing-level file (CSV)

Dataset, and Business billed yearly

GET https://gcccardeals.com/api/b2b/v1/listings.csv

One row for each priced car behind the market price tables, with the facts from its public listing, as one CSV file rebuilt every day. It comes with Dataset and with Business billed yearly, and a download counts as one call.

Parameters

Listing-level file (CSV): Parameters
ParameterRequiredDescription
marketNoOptional. It must match the market of your key; a mismatch is an error.

Example request

curl -s "https://gcccardeals.com/api/b2b/v1/listings.csv" \
  -H "Authorization: Bearer $GCC_API_KEY" \
  -o listings.csv

Example response

Illustrative values, shown to explain the format. They are not current prices, and the ad is an example.

make,model,model_year,trim,condition,mileage_km,asking_price,price_date,first_price,price_changes,first_seen,last_seen,status,city,source,url,currency,computed_on
toyota,camry,2019,GXR,used,88000,51500,2026-09-10,53000,1,2026-08-30,2026-09-16,listed,riyadh,Example marketplace,https://www.example.com/listing/12345,AED,2026-09-29

The download is named gcc-car-deals-<market>-listings-<date>.csv, with the market code and the day the file was built. It is streamed: if the connection breaks before the end, discard it, since the X-Total-Rows header tells you how many rows to expect. A key whose plan does not include the file receives a plan_limit error.

Columns

make
The make as we list it.
model
The model as we list it.
model_year
The model year.
trim
The trim the listing states, or empty when it states none.
condition
used or new.
mileage_km
The odometer reading in kilometres, or empty when the listing does not state one.
asking_price
The latest asking price we observed for the car, in the market's currency.
price_date
The date of that latest asking price.
first_price
The first asking price we saw for the car.
price_changes
How many times the asking price changed while we watched the car.
first_seen
The date we first saw the ad.
last_seen
The date we last saw the ad.
status
listed while the ad is still up, removed once it is no longer up.
city
The city the listing gives, as a lower-case name, or empty when it gives none.
source
The marketplace the ad was found on.
url
A link to the original listing, or empty in the few cases where we withhold it for privacy.
currency
The currency of every price in the answer.
computed_on
The date the table or file was computed, as a UTC date.

Price index

Available on every plan

GET https://gcccardeals.com/api/b2b/v1/price-index

The GCC Car Deals Used-Car Price Index: how much the asking price of the same kind of used car moved from one month to the next in your market, with the range each move most likely lies in. The headline for the whole market is published free of charge. This endpoint gives you every breakdown, by car age, make origin and make, from the first month of the index. It is available on every plan, and a request counts as one call.

Parameters

Price index: Parameters
ParameterRequiredDescription
segmentNoOptional. The breakdown to return, from the values listed here; leave it out to receive every breakdown. A make is written make: followed by its lower-case name, for example make:toyota. In a URL, percent-encode the plus sign of the oldest age band.allage:0-3age:4-7age:8+origin:chineseorigin:japaneseorigin:germanorigin:koreanorigin:americanmake:<make>
marketNoOptional. It must match the market of your key; a mismatch is an error.

Example request

curl -s "https://gcccardeals.com/api/b2b/v1/price-index?segment=origin:japanese" \
  -H "Authorization: Bearer $GCC_API_KEY"

Example response

Illustrative values, shown to explain the format. They are not current prices, and the ad is an example.

{
  "version": 1,
  "index": "GCC Car Deals Used-Car Price Index",
  "market": "ae",
  "method": "new-listings-v2",
  "base_month": "2026-07",
  "rows": [
    {
      "segment": "origin:japanese",
      "month": "2026-07",
      "level": 100,
      "change_pct": null,
      "change_low_pct": null,
      "change_high_pct": null,
      "same_year_change_pct": null,
      "cars": null,
      "prev_cars": null,
      "cohorts": null
    },
    {
      "segment": "origin:japanese",
      "month": "2026-08",
      "level": 100.3,
      "change_pct": 0.3,
      "change_low_pct": 0,
      "change_high_pct": 0.6,
      "same_year_change_pct": -0.4,
      "cars": 4390,
      "prev_cars": 4180,
      "cohorts": 902
    },
    {
      "segment": "origin:japanese",
      "month": "2026-09",
      "level": 99.8,
      "change_pct": -0.5,
      "change_low_pct": -0.8,
      "change_high_pct": -0.2,
      "same_year_change_pct": -1.2,
      "cars": 4460,
      "prev_cars": 4325,
      "cohorts": 915
    }
  ],
  "quota": {
    "monthly": 3000,
    "used_month": 12,
    "daily": null,
    "used_today": null
  },
  "notes": [
    "The index follows the asking prices of used cars newly listed each month, comparing like with like. These are asking prices, not transaction prices. The base month is 100."
  ]
}

Response fields

version
The response format version. Within a version, fields are added and never removed or renamed.
index
The name of the index.
market
The market the answer is for: qa, ae or sa.
method
The name and version of the method that produced the answer.
base_month
The first month of the index, as YYYY-MM. Its level is set to one hundred, and every later level is measured from it.
rows
The series: one row for each breakdown and month, the whole market first, then the breakdowns in alphabetical order, each month by month.
rows[].segment
The breakdown the row belongs to: all for the whole market, or the age band, make origin or make it covers.
rows[].month
The month the row is for, as YYYY-MM.
rows[].level
The index level: one hundred in the base month, then the previous level moved by each month's change. Where a month was too thin to publish, the series is carried over it by comparing directly with the last month that has a level. Null where that is not possible.
rows[].change_pct
How much the asking price of used cars newly listed this month moved from the month before, in percent, comparing like with like and allowing for mileage and for the cars being a month older. Null in the base month, and where the month was too thin to publish.
rows[].change_low_pct
The lower end of the range the change most likely lies in. Null when change_pct is null.
rows[].change_high_pct
The upper end of that range.
rows[].same_year_change_pct
The same comparison without allowing for the cars being a month older: how the asking price of the same model years moved. Null when change_pct is null.
rows[].cars
The newly listed cars compared this month, a car listed more than once counting once. Null in the base month, and where nothing could be compared.
rows[].prev_cars
The newly listed cars compared from the month before. Null in the base month, and where nothing could be compared.
rows[].cohorts
The like-for-like groups compared: cars of the same make, model, model year and trim family, on the same marketplace. Null in the base month, and where nothing could be compared.
quota
Your quota and how much of it you have used: monthly, used_month, daily and used_today.
notes
Plain-language notes on how to read the numbers.

Errors

A refusal returns the matching HTTP status and a JSON body with a code you can act on and a message a person can read.

Errors
StatusCodeMeaning
400bad_requestA parameter is missing or invalid. The message says which. No quota is used.
401unauthorizedThe key is missing, malformed, expired or revoked.
403plan_limitYour plan does not include this request, for example the full table on Starter, the listing-level file on a plan without it, or a date further back than your plan's history window. The message says what is missing.
422unknown_vehicleWe do not recognise the make or model, and the answer lists some models we do know. A model we list that has no comparable cars in the window is not an error: the answer has no value and says why.
429rate_limitedToo many requests in a short time. Wait the number of seconds in the Retry-After header.
429busyAnother request with this key is still running. Send one request at a time.
429quota_exceededYour monthly quota for this market is used up. It renews at the start of the next calendar month (UTC).
503unavailableThe data could not be read right now. Retry after the number of seconds in the Retry-After header. It is never an answer about the car.

Limits and quota headers

Each plan has a monthly quota of calls in every market it covers, counted from the start of the calendar month (UTC), on yearly plans too. A valuation, a market-price lookup, a price-index request and a download of the full table or the listing-level file each count as one call. Each client IP address can also send up to 120 requests a minute, and only one request per key can be in flight at a time.

A successful answer reports your quota in three headers. Two more are worth knowing.

Limits and quota headers
HeaderDescription
X-RateLimit-LimitYour quota for this market in the current period.
X-RateLimit-RemainingThe calls left in the period after this one.
X-RateLimit-ResetWhen the quota renews, as a Unix timestamp in seconds (UTC).
Retry-AfterOn a rate-limit or unavailable error: the seconds to wait before you retry.
X-Total-RowsOn the CSV download: the number of data rows in the file, to check it arrived whole.

Limits by plan

Limits by plan
PlanCalls per market per monthMarketsPast-date valuationsFull daily price table (CSV)Listing-level file (CSV)
Starter300One market of your choiceLast 90 daysNot includedNot included
Pro3,000All marketsLast 90 daysIncludedNot included
Business15,000All marketsThe whole historyIncludedIncluded when billed yearly
DatasetBilled yearly only300One market of your choiceLast 90 daysIncludedIncluded

Price history

Each market's price history starts on a fixed date. A valuation can be asked for any date (as_of) from that day, within the history window of your plan.

Price history
MarketHistory since
QatarJun 7, 2026
UAEJun 12, 2026
SaudiJun 14, 2026

Get an API key

Sign-up, payment and API keys are handled at dealers.gcccardeals.com: subscribe, then create a key for each market in your Data API dashboard.

Try the shape of the data before you subscribe: a free CSV of the price tables for the UAE.

Read the Data API terms