Live prices
Every source is priced live. How the continuous feed works, the extra at-request bid re-read on open-bidding auctions, and how to read live_price and live_price_pending.
Prices are live across every source. All seven auction sources are refreshed continuously rather than on a slow batch schedule, so the price on a search card, a facet count, a top-offer row or a detail response is a current figure and not yesterday's. There is no stale tier and no premium "real-time" upgrade — live pricing is the baseline for everything.
On top of that baseline, one category of listing gets a second refresh: a running auction with open bidding. A bid-type car can move between any two refreshes, however frequent, so when you open one of those the API re-reads its current bid from the auction house while serving your request and hands you the figure as of that instant. That extra step is what the live_price block reports.
| The live feed | The at-request bid re-read | |
|---|---|---|
| What it is | Every listing on every source, continuously refreshed | The current bid, fetched from the auction house during your request |
| Covers | All seven sources, every listing | Running auctions on sources with open bidding |
| Where you see it | Everywhere — search, facets, top offers, market data, both detail endpoints | The two detail endpoints |
| How you can tell | It is simply the price on the response | The response carries a live_price block |
| Reused for | Until the next refresh | About two minutes (live_prices.ttl_seconds) |
There is no separate real-time endpoint, and no parameter to switch on. Ask for a car's details the way you already do, and if it qualifies for the bid re-read you get the current figure automatically. The only difference you can observe is whether the response carries a live_price block.
Which sources get the bid re-read
All seven are live-priced from the continuous feed. This table is about the second refresh — which sources additionally have a per-car bid we can re-read at request time.
| Source | Bid re-read | Why |
|---|---|---|
openlane | Yes | Timed online auction with open bidding. |
ecarstrade | Yes | Timed online auction; the current bid is only published over the auction house's socket. |
auto1, encar, copart, schadeautos, japanauction | No | Live-priced from the feed like every source, but they run no open per-car bidding, so there is no separate bid to re-read. |
Do not hardcode that list — read live_prices.sites from GET /api/contract.
Reading the response
When a price was refreshed, the detail body gains:
"live_price": {
"price": 25900,
"currency": "EUR",
"source": "openlane",
"fetched_at": 1786659750
}price is the raw bid at the auction house. fetched_at is a Unix timestamp in seconds, recorded when the auction house answered — use it, not your own clock, to render an "as of" indicator. At the same time the existing price fields are overwritten with figures recomputed from that bid, so a client that ignores live_price entirely still shows the right number.
| Field | Meaning |
|---|---|
current_price | The raw current bid. Equals live_price.price. |
current_final | Bid plus fees and taxes. |
current_tax, current_tax_delivery | The recomputed tax components. |
public_price_eur | The headline price, recomputed. |
buy_now_price, buynow_final | Not touched — a buy-now figure does not move with bidding. |
Price fields are JSON numbers
Price fields are always numbers. Before contract 2026-08-18 they were serialized as strings on a normal read but as numbers whenever a live price had been refreshed — the same field, two types, switching on something a client could neither control nor predict.
- "current_price": "25600.00"
+ "current_price": 25600.0Nothing to do if you parse with Number(...), float(...) or into a dynamic type, or if your client already tolerated the live-price case. A statically typed client that declares these as strings has to retype them as numbers.
start_price current_price current_final
current_tax current_tax_delivery buy_now_price
buynow_final buynow_tax buynow_tax_delivery
final_price public_price_eur current_bgn
buynow_bgn/api/car-details returns these fields as well, at the top level of the response. On /api/auction/{site}/{id} they sit inside auction, as before.
Telling "no live price" from "cannot do live prices"
The live_price block is absent whenever the price was not refreshed, and the reasons are deliberately indistinguishable from one another in a detail response:
- The source has no live auctions at all — five of the seven never do.
- The auction has already ended.
- The car has no bids yet. Common on eCarsTrade, where a car with no current bid publishes no price at all.
- The auction is blind. Most eCarsTrade auctions are: every bid is private, so no price is published anywhere and none is inferred.
current_pricestaysnulland that is the correct, final answer — not a missing value to retry for. - The refresh allowance for this source in the current minute was already spent.
- This deployment has live prices switched off.
Its absence never means the price is stale. Every listing is live-priced from the continuous feed whether or not this block appears; the block only reports the additional at-request bid re-read, which most listings do not qualify for. To tell "this deployment cannot do the re-read" from "this car does not need one right now", read live_prices.enabled from /api/contract once at startup — on a build from before the feature the whole live_prices block is missing, which is the only way to distinguish the two.
live_price_pending: the refresh that arrived late
The refresh runs inside your request under a time budget. When the auction house is slower than that, the response goes out with the stored price and the refresh keeps running — a second or two later it completes and is cached. Nothing is lost; it just missed your response, and the body says so with live_price_pending: true.
| Response carries | What you are holding | What to do |
|---|---|---|
live_price | The current bid | Nothing. Render it. |
live_price_pending: true | The feed price; the bid re-read is still running | Repeat the same request once after ~2s. The repeat is served from cache. |
| Neither | The live feed price, and that is final for now | Nothing. This is the normal case. |
One extra read is enough — if it still carries no live_price, the upstream call failed and the car is in cooldown; stop rather than retrying. A pending response is sent with Cache-Control: no-store and X-Live-Price: pending, so a browser, CDN or shared proxy cannot answer your follow-up with the very body that missed the price.
async function vehicleWithLivePrice(site, id) {
const first = await getJson(`/api/auction/${site}/${id}`);
if (first.auction.live_price || !first.auction.live_price_pending) return first;
// The refresh missed the budget but is still running. Exactly one more read.
await new Promise((r) => setTimeout(r, 2000));
return getJson(`/api/auction/${site}/${id}`);
}Polling
A refreshed price is reused for live_prices.ttl_seconds (default 120), and Cache-Control: max-age on the response drops to match. Polling faster than the TTL returns the same figure and gains you nothing. This is per page open, not a subscription: the refresh runs once when the car is read cold and does not keep tracking the bid while you hold the page. Issue it when a vehicle is opened, not on an interval.
How much movement to expect
Worth calibrating before you build anything around this: a live price usually equals the standard one. Measured against auctions closing the same day, most running lots had not moved since the last refresh. When they had:
| Source | Proportion that had moved | Typical gap | Why |
|---|---|---|---|
openlane | Roughly one in six | €100–€300 | Bids step in fixed increments, and movement concentrates in the hours before close. |
ecarstrade | Most of them | €1,800–€5,500 | Bid cars there carry no price on the listing at all, so the standard figure can drift much further before it is corrected. |
Treat live_price as a correction, not a stream. It is the right thing to read when a user opens a vehicle. It is the wrong thing to poll in a loop, and it will not let you watch a bid climb.
Which prices get the second refresh
Only the detail path performs it. /api/search, /api/top-offers, the market intelligence endpoints and every price-based sort or filter serve the live feed price without the extra per-request call — re-reading an auction house once per row would make a 100-row page unservable.
Everything here is read only. This API observes auction prices; it never places, raises or withdraws a bid on your behalf.