live · 2h 26m · Oct 18, 8:54 PM CT

Pro plans
on this page19 sections

a data company first

The data behind Carconomics.

Use the observed-price JSON behind the site. Find request parameters, response fields, freshness and access rules for tracked listings in Chicago and Los Angeles, plus the separate NYC sample. The examples below preserve observation times and handle missing data explicitly.

data-surface.ts
endpoints     = 7 public GET read surfaces
source        = observed trip quotes · ORD + LAX (+ NYC sample)
last_observed = Oct 18, 8:54 PM CT
last_publish  = Oct 18, 9:04 PM CT
auth          = no api keys · fair use · full calendar window: calendar tier or a car unlock
posture       = documents what exists, not an aspirational spec

what people build on this

renters & tinkerers

/api/listing-calendar

One car’s observed quote surface on your schedule — a three-line diff loop that speaks up the moment any pickup date’s trip total moves in the window your access serves.

→ the price-drop watcher

hosts & analysts

/api/quant/stats

A CSV of listing-equal market medians, one honest row per run and none when support fails — the band to chart your own price against.

→ the market-median logger

researchers & journalists

/api/picks

Evidence that names its own snapshot and content ids — re-pull the exact payloads behind a badge and publish a cross-read anyone can repeat.

→ verify a badge from raw evidence

$ / start here

$ recipes#

Four copy-paste starts over the surfaces documented below — same parameters, same shapes, unavailable states respected. Sample ids and totals are illustrative; swap in real ones from any search response.

cheapest weekend, next 30 days

/api/search docs →

Four bounded requests, one per upcoming Friday — the flex planner answers each date exactly, and jq keeps the cheapest of the four.

cheapest-weekend.sh
$ # Friday pickup × 3-day trip = the weekend; default sort is price, so
$ # .listings[0] is each Friday's cheapest match — jq -s keeps the best of four
$ for F in +0w +1w +2w +3w; do
    D=$(date -v+fri -v"$F" +%F)
    curl -sG "https://carconomics.com/api/search" \
      --data-urlencode "targetDate=$D" --data-urlencode "startFlex=0" \
      --data-urlencode "model=Model 3" --data-urlencode "market=all" \
      --data-urlencode "minLength=3" --data-urlencode "maxLength=3" |
      jq -c '.listings[0] // empty | {startDate, market, price, year, url}'
  done | jq -s 'min_by(.price)'
{ "startDate": "…", "market": "lax", "price": 129, "year": 2023, "url": "https://turo.com/…" }
                                                  // sample values — run it for real ones

price-drop watcher, one listing

/api/listing-calendar docs →

One call returns the observed cells your access serves — the full window with a calendar tier or a one-time unlock, the first observed week (status "teaser", sliced under days) otherwise — write it to a file, diff against the last run, and the diff itself is the alert. Keys are absolute pickup dates, so the sliding window never fakes a change.

drop-watch.sh
$ L=1543210          # any tracked listing id — copy a listingId from any search response
$ curl -s "https://carconomics.com/api/listing-calendar?listing=$L" |
    jq -r '(if .status == "teaser" then .days else . end)   # signed-out = first observed week
           | select(.status == "ok")
           | (.windowStart | strptime("%Y-%m-%d") | mktime) as $w
           | .cells[]
           | "\($w + .[0] * 86400 | strftime("%Y-%m-%d")) \(.[1])d $\(.[2])"
             + (if .[3] == 1 then "  carried" else "" end)' > now.txt
$ touch prev.txt && diff prev.txt now.txt | tail -3    # first run: every observed cell is new
> <pickup date> 3d $141
> <pickup date> 7d $289
> <pickup date> 3d $150  carried                  // sample values — run it for real ones
$ mv now.txt prev.txt      # cron these three lines — the diff IS the price-drop alert;
                           # a vanished cell = no quote observed, never "cannot be booked"

market-median CSV logger

/api/quant/stats docs →

Duration-specific, listing-equal medians with explicit support tiers — the select() means missing evidence never writes a fake row.

median-log.sh
$ # cron this daily: one honest CSV row per run, none when the cohort lacks support
$ curl -s "https://carconomics.com/api/quant/stats?group=tesla&market=ord&length=3" |
    jq -r 'select(.status == "ok" and .support.tier != "unavailable")
           | [.observedThrough, .market, .rentalDays, .support.tier,
              .current.selectedDuration.medianPerDay,
              .current.selectedDuration.p10, .current.selectedDuration.p90]
           | @csv' >> medians.csv
$ tail -1 medians.csv
"<ISO timestamp>","ord",3,"supported",52,38,84    // sample values — run it for real ones
$ sort -u -o medians.csv medians.csv   # reran before a fresh observation? identical rows dedupe away

verify a Top Value Pick

/api/picks docs →

Pull the ranked claim with the evidence it ships, then re-find the same car, same dates, same total on the live search surface.

verify-a-pick.sh
$ # step 1 — the ranked claim, with the evidence it ships: robustness reruns + the quote
$ PICK=$(curl -s "https://carconomics.com/api/picks?group=tesla&market=ord" | jq '.markets[0].rows[0]')
$ echo "$PICK" | jq '{listingId, rank, score, topValuePick, reruns: (.robustness | length), quote: .representativeQuote}'
{ "listingId": "1543210", "rank": 1, "score": 41, "topValuePick": true, "reruns": 3,
  "quote": { "startDate": "…", "rentalDays": 3, "total": 141, "dailyRate": 47 } }

$ # step 2 — cross-read: the live search surface must show the same car at the same total
$ D=$(echo "$PICK" | jq -r '.representativeQuote.startDate')
$ N=$(echo "$PICK" | jq -r '.representativeQuote.rentalDays')
$ curl -sG "https://carconomics.com/api/search" --data-urlencode "market=ord" \
    --data-urlencode "targetDate=$D" --data-urlencode "startFlex=0" \
    --data-urlencode "minLength=$N" --data-urlencode "maxLength=$N" |
    jq --argjson p "$PICK" '.listings[] | select(.listingId == $p.listingId)
                            | {listingId, startDate, price, rentalValue}'
{ "listingId": "1543210", "startDate": "…", "price": 141,
  "rentalValue": { "score": 41, "rank": 1, "cohortSize": 118, "topValuePick": true } }
   // sample values — a fresh publication between the two reads can shift them
$ # not on page 1? walk offset=40, 80, … (page size 40, sorted by price)

01 / contract

Conventions#

Every endpoint below is the exact surface the site itself renders from. Same origin, same JSON, same honest unavailable states.

conventions.txt
base       = https://carconomics.com
format     = JSON over plain GET · no auth header
groups     = tesla (default) | luxury — never blended in one response
markets    = ord (Chicago O'Hare) | lax (Los Angeles LAX)
prices     = trip totals in USD, before taxes
timestamps = ISO 8601 UTC
dates      = ISO yyyy-mm-dd, always inside the published window

Group rule: an absent or unrecognized group parameter means Tesla on every surface, so legacy URLs keep working unchanged. Where a group must be explicit and valid (Picks, quant stats), an invalid value is HTTP 400 — never silently normalized.

03 / endpoint

GET /api/picks#

The current Rental Value rankings with their complete score evidence — or an honest unavailable state with a machine-readable reason.

GET/api/picks

Top Value Picks per market: score, rank, axis evidence, robustness passes, and the vehicle card fields, for the current genuine observation.

paramtypedefaultnotes
group"tesla" | "luxury"teslainvalid or repeated = 400 invalid_group
market"ord" | "lax" | "both"bothinvalid or repeated = 400
picks-response.jsonc
{
  "status":          "ok",              // or "unavailable" + reason (still HTTP 200)
  "group":           "tesla",
  "formulaVersion":  "…",               // exact Rental Value formula generation
  "contentId":       "…",
  "generationId":    "…",
  "observedThrough": "<ISO timestamp>",
  "publicationKind": "observation",     // or curation_rebuild | repush
  "markets": [ {
    "market":      "ord",
    "marketLabel": "Chicago · ORD",
    "evidence":    { "status": "supported", "reasons": [], "marketFreshShare": 0.99,
                     "baseEligiblePopulation": 240, "rankedPopulation": 118 },
    "rows": [ {
      "listingId": "1543210", "score": 41, "rank": 1, "cohortSize": 118,
      "topValuePick": true, "percentile": 0.99,
      "peerKind": "model", "peerValue": "Model 3", "peerCount": 62,
      "axes": { /* five fixed axes, each { value, score } */ },
      "representativeQuote": { "startDate": "<ISO date>", "rentalDays": 3, "total": 141, "dailyRate": 47 },
      "robustness": [ /* three leave-a-week-out reruns with their own verdicts */ ],
      "vehicle": { "make": "Tesla", "model": "Model 3", "year": 2023, "city": "…",
                   "rating": 4.9, "trips": 112, "allStar": true, "image": "…", "url": "…" }
    } ]
  } ]
}
curl
$ curl -s "https://carconomics.com/api/picks?group=tesla&market=ord" \
    | jq '{status, top: .markets[0].rows[0] | {listingId, score, rank, topValuePick}}'
{ "status": "ok", "top": { "listingId": "1543210", "score": 41, "rank": 1, "topValuePick": true } }

freshness · Picks fail closed on source age: an observation older than the group’s stale threshold returns status: "unavailable" with reason stale-source-observation (or invalid-observation-timestamp / future-observation-timestamp); a group published without a picks artifact reads not-yet-published. Old rankings are never served as current.

statusbodymeaning
400{ "status": "invalid", "error": "invalid_group", "retryable": false }group was supplied but is not tesla/luxury, or was repeated
400{ "status": "invalid", "message": "Choose ORD, LAX, or both markets." }market was supplied but is not ord/lax/both
503{ "status": "unavailable", "message": "…" }KV unreachable, or the payload exceeded the fixed 128 KiB response budget; search stays available

04 / endpoint

GET /api/quant/stats#

A bounded projection of the duration-specific Stats evidence: one group, one market, one exact trip length per request.

GET/api/quant/stats

Reproducible panel evidence — current listing-equal cohorts plus history series with explicit supported/thin/unavailable/collecting states.

paramtypedefaultnotes
group"tesla" | "luxury"teslainvalid or repeated = 400 invalid_group
market"ord" | "lax"ordinvalid or repeated = 400 invalid_market
lengthsupported int3must be one of the group's supported lengths (tesla 1–14, luxury 1–8); anything else = 400 invalid_length, never silently normalized
quant-stats-response.jsonc
{
  "formulaVersion": "quant-stats-1.0",
  "status":         "ok",              // or "collecting" + reason before the first verified publication
  "group": "tesla", "market": "ord", "rentalDays": 3,
  "contentId": "…", "generationId": "…", "observedThrough": "<ISO timestamp>",
  "support": { "tier": "supported",    // supported ≥30 listings · thin 10–29 · unavailable <10 or <95% fresh
               "listings": 236, "freshListings": 234, "freshShare": 0.99, "reason": "…" },
  "current": {
    "selectedDuration":  { "medianPerDay": 52, "p10": 38, "p50": 52, "p90": 84,
                           "listings": 236, "ciLo": 49, "ciHi": 55, "complete": true },
    "durationCurve":     [ /* listing-equal median $/day per exact length */ ],
    "crossMarketPriceGap": [ /* same-model ORD vs LAX medians, each with its own interval */ ],
    "allStarShare":      { /* separately gated badge share + price comparison */ },
    "listingEqualCapturedDiscount": { /* p25/p50/p75 of captured host discounts */ }
  },
  "history": {
    "selectedDurationStatus": { "state": "ready", "completeDays": 21, "requiredDays": 14 },
    "selectedDuration":       [ /* daily p10/p50/p90 for this exact duration */ ],
    "repricingStatus":        { "state": "collecting", "requiredQualifyingDays": 28, "lookbackDays": 90 },
    "marketIndexStatus":      { "state": "ready", "supportedPoints": 34, "formulaVersion": "…" },
    "marketIndex":            [ /* same-listing daily index chain, reasons included */ ]
  },
  "definitions": { "quoteWindow": "…", "support": "…" }   // the vocabulary, in the payload itself
}
curl
$ curl -s "https://carconomics.com/api/quant/stats?group=tesla&market=ord&length=3" \
    | jq '{status, tier: .support.tier, medianPerDay: .current.selectedDuration.medianPerDay}'
{ "status": "ok", "tier": "supported", "medianPerDay": 52 }

freshness · the projection is computed from the latest verified analytics-v2 publication; unsupported cohorts arrive as explicit states with reasons, never as silently substituted durations or quote-weighted fallbacks.

statusbodymeaning
400{ "status": "invalid", "error": "invalid_group" | "invalid_market" | "invalid_length", "retryable": false }the exact failing parameter, named; repeated parameters also 400
503{ "status": "error", "error": "stats_unavailable", "retryable": true }the stats snapshot could not load
503{ "status": "error", "error": "stats_projection_too_large", "retryable": true }the payload exceeded the fixed 128 KiB cap (actual size is advertised via x-stats-bytes on success)

05 / endpoint

GET /api/listing-calendar#

One tracked listing's quote surface as compact (pickup date × trip length) tuples — the full observed window for calendar-tier or unlocked sessions, the first observed week (status "teaser") for everyone else.

GET/api/listing-calendar

The premium price-and-availability calendar's data: per-cell price, carried flag, and fair-value fields when (and only when) the snapshot's pricing validated.

paramtypedefaultnotes
listing1–12 digit idrequiredthe tracked listing; anything else = 400 listing_required
group"tesla" | "luxury"teslaabsent/invalid = tesla
listing-calendar-response.jsonc
{
  "status":       "ok",               // or "untracked" — this id is not in the current snapshot
  "group":        "tesla",
  "contentId":    "…", "generationId": "…",
  "listingId":    "1543210",
  "market":       "ord",
  "urlBase":      "https://turo.com/…",
  "windowStart":  "<ISO date>",       // UNclamped market window start — the offset base
  "windowDays":   60,
  "supportedLengths": [1, …, 14],
  "failedOffsets": [17],              // pickup dates the collection could not verify — disclosed, not smoothed
  "capHits":      0,
  "observedThrough": "<ISO timestamp>",
  "staleMinutes": 24,
  "pricingValidated": false,          // false = price-only calendar; fair/save are 0
  "todayISO":     "<market-local today>",  // request-time; cells before it render as the no-claim past band
  "cells": [
    // [dayOffset, days, price, carried, fair, save] — one tuple per observed cell
    [12, 3, 141, 0, 0, 0],
    [12, 7, 289, 0, 0, 0],
    [13, 3, 150, 1, 0, 0]             // carried=1: last-seen price, not fresh this refresh
  ]
}
listing-calendar-teaser.jsonc
// The calendar gate: without a calendar tier or a per-car unlock (signed
// out included), the SAME object above arrives sliced server-side to the
// first observed week and nested under days — the tail never leaves the
// server, and nothing here is an availability claim.
{
  "status":    "teaser",
  "signedIn":  true,                // false when signed out (credits absent then)
  "credits":   2,                   // signed-in sessions only — remaining one-time unlocks
  "days":      { /* the "ok" object above, windowDays and cells cut to the first week */ },
  "totalDays": 60                   // what the full window holds
}
curl
$ curl -s "https://carconomics.com/api/listing-calendar?listing=1543210" \
    | jq '{status, windowDays, cells: .cells | length, pricingValidated}'
{ "status": "ok", "windowDays": 60, "cells": 412, "pricingValidated": false }

freshness · carried rows ship with their flag and past-dated rows ship for the past band — the provider owns the honesty of the evidence, the client owns state rendering. A missing cell means no quote observed, never a claim the car cannot be booked.

statusbodymeaning
400{ "error": "listing_required" }listing is absent or not a 1–12 digit id
200{ "status": "teaser", "days": { … } }calendar gate without a calendar tier or unlock — days carries the first observed week; totalDays names the full window
503{ "status": "unavailable" }live bindings exist but the snapshot could not load; Retry-After: 30

06 / endpoint

GET /api/preview-search + /api/preview-listing#

The NYC preview lane: a sampled Tesla tier around Newark, JFK, and Manhattan with the same planner math and a deliberately weaker, price-only vocabulary.

GET/api/preview-search

Run the shared flex planner over the sampled NYC quote matrix; one card per car with its best matching quote.

paramtypedefaultnotes
targetDateISO dateresolved from boundsclamped into the sample's window
startFlexint 0–105± days of pickup flexibility
minLength / maxLengthint4 / 0same No-max sentinel as the main planner
sortprice | perday | year | ratingpriceno value, no distance — the sample carries neither fair value nor origins
offsetint 0–20000page offset (page size 40)
GET/api/preview-listing

One sampled car's quote cells for the preview calendar; three-state vocabulary only.

paramtypedefaultnotes
listing1–12 digit idrequireda sampled NYC listing; anything else = 400 listing_required
preview-responses.jsonc
// /api/preview-search
{ "status": "ok", "marketId": "nyc", "observedAt": "<ISO timestamp>", "staleMinutes": 41,
  "sampled": { "capHits": 3, "capped": true },   // the sample publishes WITH page-cap hits
  "bounds": { "minDate": "…", "maxDate": "…" },
  "query": { /* echo */ }, "results": [ /* ≤40 cards */ ],
  "totalMatches": 96, "totalOptions": 5210, "totalCars": 129, "pageSize": 40 }

// /api/preview-listing
{ "status": "ok", "listingId": "…", "windowStart": "<ISO date>", "windowDays": 60,
  "lengths": [1, …, 14], "urlBase": "https://turo.com/…",
  "cells": [ [12, 3, 141], … ] }     // [dayOffset, days, price] — no carried/fair tuple slots

// either endpoint, any failure
{ "status": "pending" }              // best-effort surface; it never 500s the planner

freshness · sampled.capped is the tier’s defining disclosure: the sample is bounded by design, so a car or cell missing from it is a sampling fact, never an availability or market-coverage claim. Preview never computes fair value.

statusbodymeaning
400{ "error": "listing_required" }preview-listing only: listing is absent or malformed
200{ "status": "pending" }the sample blob is not readable right now — the honest fallback for every failure
200{ "status": "untracked", "listingId": "…" }preview-listing: the id is not in the current sample

07 / endpoint

GET /api/dashboard-context#

The small provenance-plus-drops payload the dashboard hydrates from: publication identity and the freshest detected price decreases.

GET/api/dashboard-context

Current publication ids and timestamps for one group, plus up to 12 recent listing-level price-drop events.

paramtypedefaultnotes
group"tesla" | "luxury"teslaabsent/invalid = tesla; arbitrary extra parameters are ignored for caching
dashboard-context-response.jsonc
{
  "source":          "live",           // "empty" = no publication yet
  "group":           "tesla",
  "contentId":       "…",
  "generationId":    "…",
  "checkedAt":       "<ISO timestamp>",
  "publishedAt":     "<ISO timestamp>",
  "observedThrough": "<ISO timestamp>",
  "drops": [ {                         // ≤12, listing-level, expire after 48h
    "listingId": "1543210", "market": "ord", "model": "Model 3", "year": 2023,
    "startDate": "<ISO date>", "rentalDays": 3,
    "oldPrice": 178, "newPrice": 141, "pct": 0.21,
    "droppedAt": "<ISO timestamp>", "city": "…", "image": "…", "url": "…"
  } ]
}
curl
$ curl -s "https://carconomics.com/api/dashboard-context?group=tesla" \
    | jq '{source, observedThrough, drops: .drops | length}'
{ "source": "live", "observedThrough": "<ISO timestamp>", "drops": 12 }

freshness · the Worker keeps a 45-second shared edge copy per group (X-Carconomics-Edge-Cache: HIT|MISS); the browser response itself is always no-store. There are no error shapes — an empty publication reads as source: "empty" with blank ids.

08 / contract

Freshness & provenance#

Every payload separates when prices were observed from when the artifact was published, and names the immutable snapshot it was computed against.

provenance.contract
observedThrough / checkedAt = when the prices were actually observed
publishedAt                 = when this exact artifact was committed
staleMinutes                = minutes since the observation, not the HTTP response
snapshotId / contentId      = immutable — same id ⇒ byte-identical evidence
generationId                = the collection generation behind the content

Thresholds: Tesla collection runs about every four hours; a Tesla observation older than 240 minutes is stale, and age-gated surfaces like Picks fail closed rather than serve it as current. Luxury’s threshold is 720 minutes, and a deliberately paused group ages by design — the site says so in prose instead of raising a false alarm. A new publication always mints a new snapshotId; search cursors are bound to it, which is exactly why a mid-pagination publication produces the 409 restart instead of a silently inconsistent page.

Carried vocabulary: inventory can flicker. A quote missing from one refresh is carried briefly with an explicit carried flag and dropped after repeated misses; fresh-only surfaces (Host Desk, action signals) exclude carried rows entirely. Nothing on any surface infers demand, bookings, or occupancy from disappearance.

Retained vocabulary: every run re-confirms availability for every tracked pickup date, but prices are re-observed inside a per-run request budget. A car that the latest search confirmed on a date whose price was not re-observed keeps its earlier price with an explicit retained flag for at most 72 hours, and the card says price from an earlier observation. In the published quote matrix each row carries one flags byte: value 1 = Steal, value 2 = carried (last-seen), value 4 = retained (observed in an earlier run, car confirmed available on that date in the latest run, kept at most 72h). Retained rows are observations of confirmed-available cars, so they join the fair-value fit and the market index like fresh rows; carried rows never do.

09 / contract

Rate limits & caching#

The current posture, stated honestly: open fair-use reads, no keys, small edge windows, and no support yet for heavy programmatic volume.

caching.today
browser        = every JSON response is Cache-Control: no-store
edge (search)  = first-page GETs (no cursor/offset, no location params)
                 keep a 45s shared copy · X-Carconomics-Cache: HIT|MISS|BYPASS
edge (context) = /api/dashboard-context keeps a 45s copy per group
origin         = ~10-minute in-memory snapshot memo per group behind every read
keys           = none required today · no rate-limit headers are sent

Fair use: these endpoints exist so anyone can verify what the site claims, and light scripted reads are welcome. Location parameters are session-only and bypass shared caching entirely. Heavy programmatic use — bulk export, sustained polling, product integrations — is not supported on the current infrastructure; the search page’s bounded pagination is deliberate, not an obstacle to route around.

10 / contract

Errors#

The complete set of shapes actually returned. Invalid input is named precisely; infrastructure trouble is retryable; missing evidence is a state, not an error.

statusbodymeaning
400{ "status": "invalid", "error": "invalid_group" | "invalid_market" | "invalid_length", "retryable": false }picks + quant stats: the exact failing parameter; invalid input is never silently normalized
400{ "error": "listing_required" }listing-calendar + preview-listing: a missing/malformed listing id
409{ "error": "search_cursor_invalid", "code": "…", "restart": true }search only: the continuation outlived its snapshot — restart from page one
503{ "error": "search_unavailable", "retry": true }search: snapshot load failed with live bindings present; Retry-After: 30
503{ "status": "unavailable" | "error", … }picks / stats / calendar: unreachable storage or a breached fixed response budget (128 KiB caps on picks and quant stats)
200{ "status": "unavailable" | "collecting" | "pending" | "untracked", … }not an error: the evidence honestly does not support a result yet, with a machine-readable reason where one exists

Reading the last row: unavailable states are first-class results. A stale source observation, an unpublished picks artifact, or a still-collecting history panel all arrive as HTTP 200 with an explicit status — the same states the site renders — so a client that only checks HTTP codes will never mistake missing evidence for a working answer.

11 / contract

Keys & access#

Everything above documents what exists today. This card is the single exception.

API keys & programmatic access — coming soon. Today every read surface on this page is open at fair-use volumes with no key. If you build against it, keep request rates polite, honor the unavailable states, and expect the shapes documented here — they are the same ones the site itself consumes.

12 / guide

The Rentals planner#

Every search is a fully specified plan: which pickup dates, which trip lengths, which cars — resolved identically on the client and the server.

Flexible dates, exact totalsopen rentals →

Flexible pickup mode starts from one target pickup date and widens it by ±0–10 days; exact date range mode tests every trip that starts and drops off inside the chosen window. The length chips set a hard minimum trip length and an optional maximum — No max searches through the current data ceiling (14 days for Tesla). Model chips filter Tesla by model and Luxury by make, and Mass Search asks the broad question: every stored pickup date across all supported lengths, or one selected length.

Every displayed number is a real quoted trip total before taxes, quoted independently per duration — because host discounts make the price curve uneven, a 5-day trip can genuinely cost less than a 4-day one. A shared URL reproduces the exact same plan, so what you send someone is what they see.

13 / guide

By car vs by exact trip#

Two projections of the same matched set: shortlist vehicles first, or pin the exact pickup and length directly.

One matched set, two viewstry by exact trip →

By car shows one card per vehicle carrying its cheapest matching trip, with a matches count for that car’s other qualifying options. By exact trip expands every (car × pickup date × length) match into its own row — useful once the vehicle is chosen and the question is purely which dates. Both views rank the identical matched set; the gap between totalVehicles and totalTrips in the response is the real depth of options, not padding. Sorting and filters apply before either projection, so the highlighted picks agree across views.

14 / guide

The price & availability calendar#

One listing's entire observed quote surface on a calendar — with a vocabulary that refuses to claim more than the evidence shows.

Every observed cell, honestly labeledopen any car card →

Open any car card and the calendar shows every observed pickup date for the selected trip length. Color encodes price within that one trip length — switch lengths and the scale recomputes, so shades are never comparable across lengths. A gold cell is a last-seen price carried across a briefly missed refresh; a dot means no quote was observed for that cell, which is a collection fact and never a claim the car cannot be booked. Collection-failed dates are listed outright rather than smoothed over.

Fair-value shading joins the calendar only when the snapshot’s pricing model validated; otherwise it stays price-only rather than borrowing an unverified model. Clicking a cell links to the listing with those exact dates prefilled.

15 / guide

Top Picks#

A fixed, rules-based ranking of resilient rental-price value. Placement cannot be bought, and weak evidence removes the badge instead of softening it.

Price-only, robustness-testedopen picks →

Rental Value scores a price basket — pickup offsets 7–27 across 1, 3, and 7-day trips — on five fixed axes, then requires a top rank, three leave-a-week-out robustness passes, and qualification in two consecutive genuine observations before the Top Value Pick badge appears. Ratings, host identity, distance, clicks, sponsorship, and commissions never enter the score or the order. When the source observation is stale or invalid the whole ranking goes unavailable rather than serving yesterday’s picks as today’s. The full axis and robustness evidence ships in the API payload, so every badge is checkable.

16 / guide

Trends & stats#

Duration-specific, listing-equal market evidence with explicit support tiers — the page tells you when a cohort is too thin to trust.

Supported, thin, or honestly absentopen stats →

Every panel answers for one market and one exact trip length, and one listing gets one vote regardless of how many quotes it has. Support is tiered: fewer than 10 listings (or under 95% fresh) is unavailable, 10–29 is thin, 30 or more is supported. The cheapest-dates heatmap normalizes color within each trip-length row, so intensity compares dates inside a row, never across rows. History panels stay in a collecting state until their day-count and completeness gates pass — no gap-filling, no substituted durations. Each panel states what it can and cannot prove; “after controls” is an association, not causation.

17 / guide

Host Desk#

Competitive context for one tracked listing from fresh like-for-like peers — and deliberately nothing about demand or revenue.

Fresh peers, bounded claimsopen host desk →

Paste a tracked listing and Host Desk builds a peer band from fresh, same-market, same-vehicle listings — trying a supported ±2-model-year cohort first, then widening honestly. Supported bands expose p25/median/p75 and your percentile; thin cohorts show only observed min/median/max and never enter the supported-only headline. Carried (last-seen) quotes are excluded — a competitive read deserves fresh evidence only. The scope is deliberately narrow: observed prices and discount overshoots, never demand, occupancy, revenue, or a recommended price, because the data cannot support those claims.

18 / guide

The energy study#

Observed rental prices joined to official EPA and EIA energy data — with the rental and energy components always shown separately.

Official sources or nothingopen the study →

The Luxury EV-vs-gas comparison combines each listing’s observed three-day rental median with an adjustable trip-energy scenario built strictly from official sources: EPA efficiency for the exact year/make/model and EIA metro gasoline and state residential electricity prices. Miles and electricity cost are yours to adjust; the rental and energy components stay visibly separate so neither can hide inside the other. The per-listing Tesla calculator is the same discipline for one car. Missing, stale, or ambiguous official inputs produce a collecting state — the study never invents an efficiency number, and an energy failure can never delay price publication.

19 / guide

The NYC preview#

A sampled Tesla tier around Newark, JFK, and Manhattan — the same planner, a smaller sample, and a vocabulary that says so.

Sampled tier, same mathopen the preview →

The preview runs the exact planner mechanics — same combo expansion, same length resolver, same sorting code — over a bounded NYC sample instead of a complete market sweep. The sample publishes with its page-cap hits disclosed, so a car or quote missing from it is a sampling fact, never an availability claim. Its vocabulary is deliberately weaker than the live markets’: price-only, no fair value, no distance sort, three calendar states instead of six. It exists to show the mechanism on a new market honestly before that market earns full collection.

Prices can change at any moment. Always confirm the final listing before booking. Sample values in response snippets are illustrative — run the curl for real ones. Carconomics is not affiliated with Turo, EPA, EIA, or any vehicle manufacturer.