← API v2 Overview

Listings

A read-only, advert-only feed of your live for-sale stock, built for syndicating to your own website. Each listing carries only public advert data - never cost, funding, purchase, reserve or customer information.

Listings vs Vehicles

Use /vehicles to manage your stock (create, update, price, publish), and /listings to publish it. The listing is a curated, stable subset of the vehicle object, scoped to what should appear in an advert, so it is safe to hand to third-parties without exposing your business data - even where a key would otherwise be over-granted.

  • Only website-published stock. A listing exists only for vehicles your published website index lists: live for-sale and reserved stock, plus recently-sold stock within your sold-retention window.
  • Advert data only. A fixed, defined field set - no cost, funding, purchase, reserve or customer fields can appear.
  • Stable shape. Defined fields are always present, with null where the vehicle has no value, so your parsing never breaks.

Marketplaces & Service Providers

Looking to integrate a marketplace or third-party service? This endpoint is linked to the website sales channel, using this means no independent control for your specific sales channel and no promotion of your service within MotorDesk. Please contact us to discuss your integration.

Access

Listings require the single listings:read scope. Issue a key with only that scope for a syndication partner: it can read listings and nothing else.

The Listing Object

A listing uses the same field names and structure as a vehicle, grouped under data. data.vehicle, data.history, data.option and data.spec mirror the vehicle response; data.stock carries only advertised pricing and identity; data.finance carries the advertised representative finance example (headline monthly plus the full breakdown).

{
  "id": 84213,
  "tag": "AB12CDEF",
  "country": "UK",
  "status": { "id": 2, "name": "for-sale", "label": "For Sale" },
  "registration": "EO68NRJ",
  "url_full": "https://example-motors.co.uk/vehicles/AB12CDEF/bmw-3-series/",
  "data": {
    "vehicle": { "type": "Car", "make": "BMW", "model": "3 Series", "derivative": "320i M Sport 4dr Auto", "fuel": "Petrol", "transmission": "Automatic", "mileage": 38450, "colour": "Black", "...": "..." },
    "history": { "year": 2020, "condition": "Used", "service_history": "Full", "...": null },
    "stock":   { "price_website": "18995.00", "price_rrp": "42000.00", "vin": "WBA8E9105HK000000" },
    "finance": { "example_monthly": "507.75", "example": { "cash_price": "20000.00", "total_deposit": "2000.00", "monthly_payment": "507.75", "total_monthly_payments": 25, "final_payment": "7856.00", "term": 27, "representative_apr": 10.9, "...": "..." } },
    "option":  { "option_custom": [], "attention": "Full Service History", "feature": {} },
    "spec":    { "engine": {}, "fuel": {}, "size": {} }
  },
  "media": [ { "url": "...", "type": "image", "position": 0 } ],
  "updated": 1781303332,
  "hash": "9b1d4c7a8f2e4a1b"
}

The full field list is in the reference below. status.name tells you whether a listing is for-sale, reserved, sold or complete.

Syndicating Stock

The recommended pattern is snapshot once, then react to events, and reconcile periodically - far cheaper than re-polling the whole feed:

  1. Initial snapshot. Page through GET /listings (cursor pagination) to build your copy.
  2. React to changes. Subscribe to the vehicle webhooks (vehicle.created, vehicle.updated, vehicle.sold, vehicle.deleted). On a change, fetch GET /listings/{id}; on sold/deleted, remove it.
  3. Reconcile. Periodically (e.g. daily) call GET /listings/manifest and diff it against your copy to self-heal any missed events.

Delta Sync

To pull only what changed since your last sync, pass updated_since (a Unix timestamp; updated_before is also supported) with cursor pagination. Each listing's updated field is your high-water mark.

GET /2.0/listings?updated_since=1781300000

A delta only returns changed records - it cannot tell you what was removed. Use the manifest (or the sold/deleted webhooks) for removals.

Manifest & Reconciliation

GET /listings/manifest returns a lightweight { id, updated, hash } entry for every live listing. Diff it against your store: ids you don't have are new, a changed hash means refetch, and ids absent from the manifest have left stock. The same hash appears on the full listing, so you can compare without recomputing.

The manifest supports conditional requests: it returns an ETag, and a subsequent request sending If-None-Match gets a 304 Not Modified when nothing has changed since your last sync, so routine polls are nearly free.

Endpoints & Fields

The Listing Object

Generated from the OpenAPI schema. Always matches the live API.

Fields (69)
AttributeTypeRequiredDescriptionExample
idinteger-Vehicle id.84213
tagstring or null-AB12CDEF
countrystring or null-UK
statusobject-Type-aware status, as GET /vehicles returns it.
status.idinteger-2
status.namestring-Status slug (e.g. for-sale, reserved, sold, complete).for-sale
status.labelstring-For Sale
registrationstring or null-EO68NRJ
url_fullstring or null-Public listing (VDP) URL on the dealer website.https://example-motors.co.uk/vehicles/AB12CDEF/bmw-3-series/
dataobject-Advert data, grouped as GET /vehicles groups it. Listed fields are always present (null when the vehicle has no value).
data.vehicleobject-Vehicle attributes.
data.vehicle.typestring or null-Vehicle class.Car
data.vehicle.makestring or null-BMW
data.vehicle.modelstring or null-3 Series
data.vehicle.generationstring or null-Saloon (2019 - 2023)
data.vehicle.derivativestring or null-320i M Sport 4dr Auto
data.vehicle.trimstring or null-M Sport
data.vehicle.bodystring or null-Saloon
data.vehicle.fuelstring or null-Petrol
data.vehicle.transmissionstring or null-Automatic
data.vehicle.drivetrainstring or null-RWD
data.vehicle.doorsinteger or null-4
data.vehicle.seatsinteger or null-5
data.vehicle.colourstring or null-Black
data.vehicle.colour_namestring or null-Manufacturer colour name.Sapphire Black
data.vehicle.engine_sizestring or null-2.0
data.vehicle.mileageinteger or null-38450
data.vehicle.registeredstring or null-First registration date (YYYY-MM-DD).2020-03-01
data.vehicle.driver_positionstring or null-RHD
data.vehicle.interior_upholsterystring or null-Leather
data.vehicle.interior_colourstring or null-Black
data.vehicle.exterior_finishstring or null-Metallic
data.vehicle.bedroom_layoutstring or null-Bedroom layout (caravans/motorhomes).
data.vehicle.end_layoutstring or null-End layout (caravans/motorhomes).
data.vehicle.bedroominteger or null-Bedrooms (caravans/motorhomes).2
data.vehicle.berthinteger or null-Berths (caravans/motorhomes).4
data.vehicle.seat_beltinteger or null-Belted seats (caravans/motorhomes).4
data.vehicle.wheelchairstring or null-Wheelchair accessible (Yes/No).No
data.historyobject-
data.history.yearinteger or null-2020
data.history.conditionstring or null-Used
data.history.keysinteger or null-Number of keys supplied.2
data.history.service_historystring or null-Full
data.stockobject-
data.stock.price_websitestring or null-Advertised website price (2dp decimal string), or null for POA.18995.00
data.stock.price_rrpstring or null-Manufacturer RRP (2dp decimal string).42000.00
data.stock.vinstring or null-WBA8E9105HK000000
data.financeobject-Representative finance, as GET /vehicles data.finance returns it. Always present; example_monthly and example are null when the vehicle has no finance example.
data.finance.example_monthlystring or null-Advertised representative monthly payment (2dp decimal string); null when finance is not enabled.507.75
data.finance.exampleobject or null-Representative finance example as shown on the advert; null when none has been generated. Figures are illustrative and subject to status.
data.finance.example.cash_pricestring or null-Cash price.20000.00
data.finance.example.total_depositstring or null-Total deposit.2000.00
data.finance.example.total_creditstring or null-Total amount of credit.18000.00
data.finance.example.first_paymentstring or null-First payment.507.75
data.finance.example.monthly_paymentstring or null-Regular monthly payment.507.75
data.finance.example.total_monthly_paymentsinteger or null-Number of monthly payments.25
data.finance.example.final_paymentstring or null-Final payment.7856.00
data.finance.example.terminteger or null-Agreement duration in months.27
data.finance.example.admin_feestring or null-Admin fee.0.00
data.finance.example.option_purchase_feestring or null-Option to purchase fee.10.00
data.finance.example.interest_chargestring or null-Total interest charges.3057.50
data.finance.example.total_payablestring or null-Total amount payable.23057.50
data.finance.example.fixed_interest_ratenumber or null-Annual fixed interest rate (percent).10.36
data.finance.example.representative_aprnumber or null-Representative APR (percent).10.9
data.optionobject-Full option section, as GET /vehicles data.option (option_custom, attention, description, website, feature).
data.specobject-Full spec section, as GET /vehicles data.spec (performance, engine, battery, fuel, size, insurance, other).
mediaarray of object-Ordered advert media, as GET /vehicles returns it.
updatedinteger-Unix timestamp last updated (use for delta sync).1781303332
hashstring-Change token, identical to the manifest entry hash for this listing.9b1d4c7a8f2e4a1b
Example object
{
    "id": 84213,
    "tag": "AB12CDEF",
    "country": "UK",
    "status": {
        "id": 2,
        "name": "for-sale",
        "label": "For Sale"
    },
    "registration": "EO68NRJ",
    "url_full": "https://example-motors.co.uk/vehicles/AB12CDEF/bmw-3-series/",
    "data": {
        "vehicle": {
            "type": "Car",
            "make": "BMW",
            "model": "3 Series",
            "generation": "Saloon (2019 - 2023)",
            "derivative": "320i M Sport 4dr Auto",
            "trim": "M Sport",
            "body": "Saloon",
            "fuel": "Petrol",
            "transmission": "Automatic",
            "drivetrain": "RWD",
            "doors": 4,
            "seats": 5,
            "colour": "Black",
            "colour_name": "Sapphire Black",
            "engine_size": "2.0",
            "mileage": 38450,
            "registered": "2020-03-01",
            "driver_position": "RHD",
            "interior_upholstery": "Leather",
            "interior_colour": "Black",
            "exterior_finish": "Metallic",
            "bedroom_layout": "",
            "end_layout": "",
            "bedroom": 2,
            "berth": 4,
            "seat_belt": 4,
            "wheelchair": "No"
        },
        "history": {
            "year": 2020,
            "condition": "Used",
            "keys": 2,
            "service_history": "Full"
        },
        "stock": {
            "price_website": "18995.00",
            "price_rrp": "42000.00",
            "vin": "WBA8E9105HK000000"
        },
        "finance": {
            "example_monthly": "507.75",
            "example": {
                "cash_price": "20000.00",
                "total_deposit": "2000.00",
                "total_credit": "18000.00",
                "first_payment": "507.75",
                "monthly_payment": "507.75",
                "total_monthly_payments": 25,
                "final_payment": "7856.00",
                "term": 27,
                "admin_fee": "0.00",
                "option_purchase_fee": "10.00",
                "interest_charge": "3057.50",
                "total_payable": "23057.50",
                "fixed_interest_rate": 10.36,
                "representative_apr": 10.9
            }
        },
        "option": {},
        "spec": {}
    },
    "media": [
        {}
    ],
    "updated": 1781303332,
    "hash": "9b1d4c7a8f2e4a1b"
}

Endpoints

GET List Stock Listings

GET /2.0/listings · scope listings:read

Public advert view of for-sale, reserved and recently-sold stock for syndication. Supports delta sync (updated_since + cursor). Excludes all business, cost, funding and customer data by construction.

Parameters (16)
ParameterInTypeRequiredDescriptionExample
pagequeryinteger-Page number, starting at 1 (offset pagination).
per_pagequeryinteger-Results per page (maximum 500).
cursorquerystring-Cursor pagination: pass the previous page's meta.pagination.next_cursor to continue from that point instead of page. Stable while the set changes underneath, so preferred for delta sync; a null next_cursor means the end.
makequerystring-Exact match, or use % for wildcard matching (requires search:wildcard, minimum 3 characters).BMW
modelquerystring-Exact match, or use % for wildcard matching (requires search:wildcard).3 Series
fuelquerystring-Exact match, or use % for wildcard matching (requires search:wildcard).Petrol
transmissionquerystring-Exact match, or use % for wildcard matching (requires search:wildcard).Automatic
bodyquerystring-Exact match, or use % for wildcard matching (requires search:wildcard).Saloon
colourquerystring-Exact match, or use % for wildcard matching (requires search:wildcard).Black
yearquerystring-Exact match, or a two-element array [from, to] for a range (e.g. year[]=2020&year[]=2023). An empty bound is open-ended.
mileagequerystring-Exact match, or a two-element array [from, to] for a range. An empty bound is open-ended.
pricequerystring-Advertised website price. Exact match, or a two-element array [from, to] for a range. An empty bound is open-ended.
updated_sincequeryinteger-Unix timestamp; only listings changed at or after this time (delta sync).
updated_beforequeryinteger-Unix timestamp; only listings changed before this time.
cursorquerystring-Keyset pagination cursor from a previous response's meta.pagination.next_cursor. When supplied, page/total are not returned.
fieldsquerystring-Comma-separated dot-paths to return only those fields, e.g. id,data.stock.price_channel.
Responses
StatusDescription
200 OKPaginated listings

Failures use the standard error responses (4xx/5xx) with the shared error envelope.

{
    "success": true,
    "data": [
        {
            "id": 84213,
            "tag": "AB12CDEF",
            "country": "UK",
            "status": {
                "id": 2,
                "name": "for-sale",
                "label": "For Sale"
            },
            "registration": "EO68NRJ",
            "url_full": "https://example-motors.co.uk/vehicles/AB12CDEF/bmw-3-series/",
            "data": {
                "vehicle": {
                    "type": "Car",
                    "make": "BMW",
                    "model": "3 Series",
                    "generation": "Saloon (2019 - 2023)",
                    "derivative": "320i M Sport 4dr Auto",
                    "trim": "M Sport",
                    "body": "Saloon",
                    "fuel": "Petrol",
                    "transmission": "Automatic",
                    "drivetrain": "RWD",
                    "doors": 4,
                    "seats": 5,
                    "colour": "Black",
                    "colour_name": "Sapphire Black",
                    "engine_size": "2.0",
                    "mileage": 38450,
                    "registered": "2020-03-01",
                    "driver_position": "RHD",
                    "interior_upholstery": "Leather",
                    "interior_colour": "Black",
                    "exterior_finish": "Metallic",
                    "bedroom_layout": "",
                    "end_layout": "",
                    "bedroom": 2,
                    "berth": 4,
                    "seat_belt": 4,
                    "wheelchair": "No"
                },
                "history": {
                    "year": 2020,
                    "condition": "Used",
                    "keys": 2,
                    "service_history": "Full"
                },
                "stock": {
                    "price_website": "18995.00",
                    "price_rrp": "42000.00",
                    "vin": "WBA8E9105HK000000"
                },
                "finance": {
                    "example_monthly": "507.75",
                    "example": {
                        "cash_price": "20000.00",
                        "total_deposit": "2000.00",
                        "total_credit": "18000.00",
                        "first_payment": "507.75",
                        "monthly_payment": "507.75",
                        "total_monthly_payments": 25,
                        "final_payment": "7856.00",
                        "term": 27,
                        "admin_fee": "0.00",
                        "option_purchase_fee": "10.00",
                        "interest_charge": "3057.50",
                        "total_payable": "23057.50",
                        "fixed_interest_rate": 10.36,
                        "representative_apr": 10.9
                    }
                },
                "option": {},
                "spec": {}
            },
            "media": [
                {}
            ],
            "updated": 1781303332,
            "hash": "9b1d4c7a8f2e4a1b"
        }
    ],
    "meta": {
        "pagination": {
            "page": 0,
            "per_page": 0,
            "total": 0,
            "total_pages": 0,
            "next_cursor": ""
        }
    }
}

GET Get a Stock Listing

GET /2.0/listings/{id} · scope listings:read

Retrieve a single listing by vehicle id.

Parameters (2)
ParameterInTypeRequiredDescriptionExample
idpathstringYesResource identifier in the path.
fieldsquerystring-Comma-separated dot-paths to return only those fields, e.g. id,data.stock.price_channel.
Responses
StatusDescription
200 OKGet a Stock Listing

Failures use the standard error responses (4xx/5xx) with the shared error envelope.

{
    "success": true,
    "data": {
        "id": 84213,
        "tag": "AB12CDEF",
        "country": "UK",
        "status": {
            "id": 2,
            "name": "for-sale",
            "label": "For Sale"
        },
        "registration": "EO68NRJ",
        "url_full": "https://example-motors.co.uk/vehicles/AB12CDEF/bmw-3-series/",
        "data": {
            "vehicle": {
                "type": "Car",
                "make": "BMW",
                "model": "3 Series",
                "generation": "Saloon (2019 - 2023)",
                "derivative": "320i M Sport 4dr Auto",
                "trim": "M Sport",
                "body": "Saloon",
                "fuel": "Petrol",
                "transmission": "Automatic",
                "drivetrain": "RWD",
                "doors": 4,
                "seats": 5,
                "colour": "Black",
                "colour_name": "Sapphire Black",
                "engine_size": "2.0",
                "mileage": 38450,
                "registered": "2020-03-01",
                "driver_position": "RHD",
                "interior_upholstery": "Leather",
                "interior_colour": "Black",
                "exterior_finish": "Metallic",
                "bedroom_layout": "",
                "end_layout": "",
                "bedroom": 2,
                "berth": 4,
                "seat_belt": 4,
                "wheelchair": "No"
            },
            "history": {
                "year": 2020,
                "condition": "Used",
                "keys": 2,
                "service_history": "Full"
            },
            "stock": {
                "price_website": "18995.00",
                "price_rrp": "42000.00",
                "vin": "WBA8E9105HK000000"
            },
            "finance": {
                "example_monthly": "507.75",
                "example": {
                    "cash_price": "20000.00",
                    "total_deposit": "2000.00",
                    "total_credit": "18000.00",
                    "first_payment": "507.75",
                    "monthly_payment": "507.75",
                    "total_monthly_payments": 25,
                    "final_payment": "7856.00",
                    "term": 27,
                    "admin_fee": "0.00",
                    "option_purchase_fee": "10.00",
                    "interest_charge": "3057.50",
                    "total_payable": "23057.50",
                    "fixed_interest_rate": 10.36,
                    "representative_apr": 10.9
                }
            },
            "option": {},
            "spec": {}
        },
        "media": [
            {}
        ],
        "updated": 1781303332,
        "hash": "9b1d4c7a8f2e4a1b"
    }
}

Manifest

GET Stock Listing Manifest

GET /2.0/listings/manifest · scope listings:read

Lightweight {id, updated, hash} for every live listing, for cheap reconciliation: diff against your copy to find adds, changes and removals (absent ids are gone).

Parameters (2)
ParameterInTypeRequiredDescriptionExample
cursorquerystring-Keyset pagination cursor from a previous response's meta.pagination.next_cursor. When supplied, page/total are not returned.
fieldsquerystring-Comma-separated dot-paths to return only those fields, e.g. id,data.stock.price_channel.
Responses
StatusDescription
200 OKStock Listing Manifest

Failures use the standard error responses (4xx/5xx) with the shared error envelope.

{
    "success": true,
    "data": [
        {
            "id": 84213,
            "updated": 1781303332,
            "hash": "9b1d4c7a8f2e4a1b"
        }
    ],
    "meta": {
        "pagination": {
            "page": 0,
            "per_page": 0,
            "total": 0,
            "total_pages": 0,
            "next_cursor": ""
        }
    }
}