{
  "name": "InferIndex",
  "version": "0.6.0",
  "endpoints": {
    "/cheapest?model=deepseek/deepseek-v3.2": "Cheapest offer for a tracked model, across all sources (direct providers and aggregators)",
    "/resellers?model=deepseek/deepseek-v3.2": "Current prices from every provider, direct and via aggregators",
    "/history?model=deepseek/deepseek-v3.2&days=30&granularity=day&provider=DeepInfra&limit=1000&cursor=": "Price history (raw, day or week), cursor-paginated; official_prices gives the lab's official price over time, back to 2023",
    "/history?model=deepseek/deepseek-v3.2&at=2026-09-15": "Price of each offer in effect at a given date (USD at the ECB rate of that day)",
    "/history?model=deepseek/deepseek-v3.2&from=2026-09-14&to=2026-09-20&granularity=day": "History over an explicit period, instead of days",
    "/history?model=deepseek/deepseek-v3.2&series=cheapest&days=30": "Cheapest offer of each day: the offer /cheapest would have selected at 00:00 UTC (default filters), one point per day (granularity=week: one point per week, on Mondays)",
    "/models?search=deepseek": "Search models",
    "/trending": "Trending models right now (refreshed every hour): rank, model id and name",
    "/provider-ranking": "Providers ranked by how far below or above the market their prices are (refreshed every hour): for each provider, score_pct (median gap of its blended 3:1 price to the median price of the providers of each model it sells, negative when cheaper), models_measured (models with at least min_providers comparable providers), cheapest_count (models where it holds the offer /cheapest selects) and rank (from min_models models measured, otherwise null)",
    "/rankings?model=deepseek/deepseek-v3.2": "Rank of a model in public leaderboards we cite, never computed by us: for each leaderboard, the name the source lists the model under, its rank (the source's own, unique by score), rank_best and rank_worst (the source's rank spread: the best and worst rank the model can hold given every ranked model's confidence bounds; null without bounds), the number of models ranked, its score with the source's interval, the publication date and the date we read it. Each line carries scale: what the score is called, how many decimals to show, whether it can be negative, what the interval is, and what the count is (votes or observations); scores of different leaderboards are not on the same scale. Read once a day; a reading older than 30 days is not served, and neither is a leaderboard its source published more than 45 days ago. An empty list means the source does not rank this model",
    "/index/archive/2026-10-05/publication.json": "Archived copy of a published market index, byte for byte as archived at publication (and one file per correction); its sha256 is listed under archives in /index, so anyone can check the file was never changed",
    "/index?series=market&at=2026-10-05": "Weekly market index (published every Monday 00:00 UTC from 2026-10-05): median price per model family in USD per 1M tokens (blended 3:1), with the models counted and the method version; series=market (offers we collect) or official (lab list prices we collect). Each family also gives change_on_same_models_pct: the change in %, since the previous publication (named in compared_to), of the median of the models counted in both publications, so a model entering or leaving a family does not move the figure. same_models is the number of those models (the change is null without a previous publication or with fewer than 3 same models), and models_entered and models_left list the models that entered or left the family. From 2026-10-19, a model touched by an identity correction during the week (an offer moved to another model, or an official redirect applied) is left out of that change and listed in excluded_from_change with the reason, fixed at publication; the family value still counts it. From 2026-11-02, series=market may carry comment: { en, fr }, the week's short commentary written by our writer from the published data (every figure inserted by code; a family whose models changed is never described as a price movement); absent until published",
    "/health/ready": "Service status",
    "/privacy": "Privacy policy",
    "/terms": "Terms of use",
    "/mcp": "MCP server for AI assistants (Streamable HTTP, POST): tools search_models, cheapest, compare_providers, price_history, estimate_cost, provider_ranking",
    "/gpus": "GPU types tracked for rental prices, with the lowest price of each tier (guaranteed, community, spot) and how many providers offer it",
    "/gpu-rentals?gpu=h100-sxm-80gb": "Rental offers for this GPU: price in USD per GPU per hour, one block per tier, each with its own cheapest offer, never compared across tiers",
    "/self-host?model=qwen/qwen3-32b&tokens_per_day=50000000": "Is it cheaper to host this open model yourself on rented GPUs, or to use the cheapest API? A one-sentence verdict (headline), then the detail: configuration, GPU price, break-even volume and utilization, three throughput scenarios. An estimate: confidence says how the throughput was obtained"
  },
  "filters": {
    "/cheapest": "min_context, quantization (fp8,fp4,...), min_uptime (observed by an aggregator, not measured by InferIndex), tools=true, json=true, vision=true, region=eu|us|..., no_training=true, no_waitlist=true (sign-up open to everyone: no waitlist, invitation or country restriction), include_tiers=flex,batch, include_stale=true (offers not rechecked recently), strict=true (exclude offers missing the filtered data), explain=true (excluded offers and reasons), prompt_tokens, output_tokens, cached_ratio, requests_per_day (estimated cost; offers whose context window is smaller than prompt_tokens + output_tokens are excluded, unknown context flagged), sort=blended|input|output|estimated_cost (default blended, the 3:1 mix; estimated_cost, the cost of your load, when prompt_tokens or output_tokens is given), offers=false (winner and counts only), limit=1..500 (first N offers), detail=compact|full (default full; compact: the winner without empty fields and one short line per other offer, for assistants)",
    "/resellers": "region, no_training=true, no_waitlist=true, strict=true, include_tiers=flex,batch, prompt_tokens, output_tokens, cached_ratio, requests_per_day, sort, limit=1..500 (default 100), cursor (next_cursor of the previous page, same sort), detail=compact|full (default full; compact: the winner without empty fields and one short line per other offer, for assistants)",
    "/history": "days or from/to or at, granularity=raw|day|week, provider, limit, cursor, series=cheapest (cheapest offer of each day at 00:00 UTC; days or from/to only; granularity=day up to 400 days or week up to 1500 days)",
    "/gpu-rentals": "gpu (id from /gpus), tier=guaranteed|community|spot, gpu_count=1|2|4|8|16 (the published configuration), region, limit=1..50 offers per tier (default 10)",
    "/self-host": "model (id from /models, required), tokens_per_day, or requests_per_day with prompt_tokens and output_tokens (without a volume you still get the verdict and the break-even volume), utilization=1..100 (percent of the time the GPUs serve requests, default 50), tokens_per_second (your own measured throughput, input and output tokens together, instead of our estimate), weights_margin=50..95 (whole percent of the GPU memory the model weights may fill, default 70: the rest is the engine's reserve and the context cache), gpu (id from /gpus) and gpu_count=1|2|4|8|16 to impose a configuration, quantization=fp16|bf16|fp8|int8|fp4|int4 (default fp8), tier=guaranteed|community|spot (default guaranteed), detail=compact|full (default full)"
  },
  "signals": {
    "below_official_list": "Resold clearly below the lab's own list price, without a declared discount. On an offer for a retired model id served by another model (served_model), the old price is not what the lab bills: never selected by /cheapest (reason redirect_below_list)",
    "below_market": "Input and output prices are both more than 15 times below the median of the model's other providers (at least 3), and the price is not verified yet (verified: read at the same value by two independent reads of ours). An offer with a declared discount is judged on its price before the discount. The offer stays listed, never selected as cheapest. Object { ratio, median_input_per_1M, median_output_per_1M, providers }, where ratio is how many times below the median on the side that is less far below (input or output), to one decimal; absent otherwise",
    "backend_unknown": "Router price billed by the router itself, without naming the provider that serves the model",
    "aggregated_price": "Single price published by a gateway for several unnamed backends: never selected by /cheapest",
    "deactivated_by_seller": "The seller's own model page shows this provider as deactivated (read daily on the gateway's page), or the seller's catalog marks this offer unavailable, or the end date the seller publishes for this offer in its catalog has passed: the offer stays listed and is never selected by /cheapest",
    "provider_deprecated": "The provider's own public retirement schedule (Azure, learn.microsoft.com) lists this model version as Deprecated, meaning no longer available to new customers, and the model has been retired by its lab. This is a decision of ours, not a statement by the provider that the service stopped: existing deployments keep working and any availability an aggregator observed stays published in retired_by_lab_served. The offer stays listed with the schedule's date in retirement and is never selected by /cheapest, from the day the schedule is read, before that date; the date passing, or the schedule turning the version to Retired, never makes it selectable again. Nothing is closed and no price changes",
    "uptime_zero": "The aggregator that sells this offer reports 0% availability over the last 30 minutes (uptime_30m is 0; observed by the aggregator, not measured by InferIndex); the offer stays listed and is never selected by /cheapest until it reports more",
    "below_lab_price_unproven": "This offer for a closed model is priced below its lab's official price and apart from the other sellers, and no fresh proof of its own line was found in the last 72 hours; the offer stays listed and is never selected by /cheapest until there is",
    "price_differs_from_page": "The price we publish for this offer differs from the price on the seller's page (found by our own cross-check of that page); the offer stays listed and is never selected by /cheapest until both agree again",
    "not_verified": "The provider and the price of this offer were not found on a public page in the last 72 hours; the offer stays listed and is never selected by /cheapest until they are",
    "no_public_page": "No public page shows the price of this offer (offer_url is null), so nothing can verify it; the offer stays listed and is never selected by /cheapest",
    "provider_price_not_shown": "The price is specific to a provider served through a gateway, and the gateway's linked page does not show that provider with that price (it shows one price per model, or none); the offer stays listed and is never selected by /cheapest",
    "points_based": "Price converted from the source's points or credits (the amount paid depends on how points are bought): never selected by /cheapest"
  },
  "freshness": "/cheapest and /resellers: the last computed response, up to 30 minutes old, is served at once and refreshed in the background. Headers: Age (seconds), X-InferIndex-Computed-At. Each offer's checked_at is the last time its price was read.",
  "rate_limits": {
    "429": "Too many requests in the current clock minute (UTC): RateLimit-Reset and Retry-After give the seconds left until the next minute, RateLimit-Limit the limit that applied. The body is { error }, plus hint for a caller without a key: where to get a free key. Never cached",
    "without_key": "60 requests per minute per IP address on /cheapest, /history, /resellers, /self-host, /gpus and /gpu-rentals, counted on requests that are not served from cache",
    "with_key": "300 requests per minute per key on those routes, sent in the x-api-key header. A key is optional and free"
  },
  "model_fields": {
    "new_listing": "New model, listed at listed_at: its prices are being verified until verifying_until (48 hours without an open anomaly). Published as soon as at least 2 independent sources list it; null otherwise",
    "retirement": "In /cheapest and /resellers: the announced end of the model, { date, source_url, read_at, replaced_by? }, same shape as the offer field retirement. Given when the model's own lab announces it, or when every seller currently listing the model has announced a date (then the latest of them); one seller dropping a model that others keep selling is said on its offers only. effective: true is added once the date has passed while the official page still carries it: the model is retired by its lab, and the offers whose provider is that lab are listed but no longer selected; other providers keep theirs until their own announced date. date_kind: \"earliest\" is added when the lab's page marks the model as already shut down (a grey row on Google's deprecations page) without a firm date: effective is then true and date is only the earliest date that page gives, never the day the model was retired. A grey row is held back while a recent measurement (less than 48 hours old) shows an offer of the lab still serving the model. null otherwise"
  },
  "offer_fields": {
    "not_verified": "Why the offer is listed but never selected as the cheapest, given only when verified is false: { reason, last_proof_at }. reason: retired (the model's lab has retired it, and this seller has not shown it on sale on a public page in the last 72 hours), serverless_page (the seller's page for this model was not read, or says it is not sold per token), no_public_page (no public page of this offer is known), provider_price_not_shown (the linked page does not show this provider with this price), below_lab_price_unproven (for a closed model, priced below its lab's official price and apart from the other sellers, with no fresh proof of its own line in the last 72 hours), not_found (the seller and price were not found on its public page in the last 72 hours). One reason per offer, the first that applies in this order. last_proof_at: when they were last found, or null. In detail=compact, not_verified is the reason alone",
    "conditions": "Conditions published for this offer: conditions.provider for the provider, conditions.via for the aggregator it is sold through, if any. Each condition is { value, code, source_url, checked_at }, where checked_at is when we last found its quoted passage on source_url. stale: true when a known condition was not rechecked within 8 days (our weekly review, plus one day), was never confirmed, or its quoted passage was not found at the last review: it is the last published value, not a confirmed one. In detail=compact, stale stays on each condition, and training_on_prompts.stale lists which of provider and via were not rechecked",
    "retirement": "The seller of this offer has announced that it stops serving the model: { date (YYYY-MM-DD), source_url (the seller's or the lab's official page), read_at (when we last read that date on that page), replaced_by (id of the model named as replacement, when we track it) }. Given only while the official page carries that date word for word and was read again within the last 7 days. Once the date has passed and the page still carries it, effective: true is added and the offer is listed but never selected (deactivated_by_seller). Azure's public retirement schedule, for a model its lab has retired: a version it lists as Deprecated or Retired carries the schedule's date, and the offer is not selected, before and after that date (provider_deprecated, then deactivated_by_seller once effective). effective: true is added only when the date has passed and the last successful reading of the schedule confirmed the row. Such a line does not lapse after 7 days, and a row leaving the page never makes the offer selectable again. Only when the schedule reads the row as GA on two identical readings at least 12 hours apart is the line withdrawn, and the offer may then be selected again under the usual rules. It never changes the price. Absent otherwise (the key is left out, not set to null, unlike model.retirement): no date known to us, which never means the model stays. In detail=compact, a short line carries the signal retiring (retired once effective, so a schedule line stays retiring after retires_on until confirmed) and retires_on (the date)",
    "offer_url": "The public page of the seller of the offer, where it can be checked. Either the seller's pricing page or, when kind is \"offer\", the seller's own page for this model, formed from the seller's page pattern and its own identifier for the model and checked before publication. Never formed from our identifiers. null when no reliable page is known.",
    "offer_url_kind": "What offer_url leads to: pricing (the seller's pricing or model-list page, not this offer alone) or offer (the seller's own page for this model); null without offer_url. An address is offer only after the page was checked (it answers, without a redirect to the home page or to a list), and it is checked again every 7 days; when it stops answering, the offer goes back to the seller's pricing page and pricing. A page can change between two checks: treat any other value as pricing.",
    "seller_url": "The home page of the seller of the offer (the named aggregator when the offer is sold through one, otherwise the provider). Given only when no public price page is known for that offer (offer_url is then null); it shows no price. null otherwise",
    "price_context": "What the displayed price is, as a list of entries (empty for a plain price). scheduled: off-peak price of a published time-of-use schedule, peak price given apart (never a promotion). off_peak_unknown_hours: added next to scheduled when the seller publishes an off-peak and a peak price but not its hours (scheduled.hours is null): the price shown only applies at hours we cannot state, so the offer stays listed and is never selected as cheapest. unreadable_tiers: the seller publishes price tiers we could not read; the price shown is its first one, so the offer stays listed and is never selected as cheapest. promotion: discount announced by the provider (source provider) or confirmed when the price came back (source history), with ends_at when published. price_drop_observed: drop seen in the price history (promo = \"probable\"), never shown as a promotion; a discount declared by the provider with no announced end date for 14 days or more is shown the same way, with the price before the discount in price_before_promo (a lasting price is not a promotion). below_lab_list: resold below the lab's official list price without a declared discount. outdated_price (reason redirected_id): old price of a retired model id now served by another model (requested_model, served_model), below that model's list price; not a discount, never selected as the cheapest. unstable_price: the price changed at least 8 times in the last 7 days; it carries changes, window_days and the observed range (input_per_1M and output_per_1M, min and max): the offer stays listed at its place, but is not selected as the cheapest offer by the API: the next offer is, if there is one. service_tier: flex, batch or priority. cached_input: price of cached input tokens, separate from input_per_1M. Every discount (0 to 1, blended price) names its reference: peak, provider_usual, previous_price or lab_list"
  },
  "gpu_fields": {
    "usd_per_gpu_hour": "Price of one GPU for one hour, in USD, as published by the provider for the configuration in gpu_count",
    "tier": "guaranteed: capacity the provider presents as not interrupted; community: third-party hosts; spot: interruptible capacity. As published by the provider. Each tier has its own cheapest offer",
    "gpu_count": "Number of GPUs in the published configuration. The price per GPU can differ between configurations: compare offers with the same gpu_count (cheapest_by_gpu_count)",
    "billing": "second, minute or hour, only when the provider publishes it",
    "stale": "The provider's price list could not be re-checked recently: the offer is listed last and is never the cheapest"
  },
  "self_host_fields": {
    "verdict": "api_cheaper: the API is cheaper at any volume. self_host_cheaper_above: self-hosting is cheaper above threshold_m_tokens_per_day at your utilization. self_host_above_utilization: the API is cheaper at your utilization, but self-hosting wins above the break-even utilization. self_host_needs_throughput: the throughput scenarios disagree, or no throughput is known for this model on this GPU; the headline then gives the break-even volume and the throughput required (required_tokens_per_second)",
    "required_tokens_per_second": "Minimum throughput, in input plus output tokens per second, that the whole configuration (all GPUs together) must deliver while serving for self-hosting to cost less than the API: at_full_utilization if it were busy all the time, at_utilization at the utilization you gave (utilization_percent). Compare with your measured tokens_per_second. With a volume, for_your_volume gives the same two figures for serving that volume itself rather than the break-even volume; the headline quotes them when no throughput is known. Null when the API offer is free",
    "break_even_utilization_percent": "Per scenario (prudent, median, optimistic): the average utilization above which self-hosting costs less than the API, whatever the number of GPUs. Above 100 means never at that throughput",
    "confidence": "How the throughput was obtained: measured (published for this model and configuration), derived, estimated (wide range), lower_bound (a published benchmark gives a floor of the throughput: it can decide that self-hosting wins, never that the API is cheaper), user_supplied (your tokens_per_second), none (unknown: no throughput is known for this model on this configuration, and the verdict would need one), not_needed (the verdict does not rest on any throughput: at or under the break-even volume, or when the API offer is free, the API is cheaper whatever the throughput)",
    "configuration": "The rented configuration the verdict is about. throughput_evidence says what is known about the throughput of this configuration (measured, derived, estimated, lower_bound, user_supplied, none); confidence says what the verdict rests on, so the two can differ (a volume under the break-even with a published minimum: lower_bound and not_needed)",
    "throughput": "When status is lower_bound: a published benchmark (named in source) gives a floor, not the capacity. published_output_tokens_per_second is what it measured (output tokens per second for the whole configuration, 1,024-token prompts and answers; its series stopped while throughput was still rising). at_least_tokens_per_second is that figure converted to input plus output tokens per second for your mix (conversion says how). sufficient_utilization_percent is an occupancy at which the floor alone makes self-hosting cheaper above the break-even volume (sufficient, not necessary: below it the real capacity may still be enough); null if it never is, or if your requests exceed 2,048 tokens in total. engine is the inference engine of the benchmark run: one of vllm, sglang, trtllm, other, or null when unknown. other_engine_ceiling, when present: on the same setup another series (its engine has the same possible values) levelled off (our reading) at a lower figure in the same benchmark; that is not the capacity of the configuration, and we do not use it",
    "headline_kind": "Which sentence the headline is, as a stable value, so that a client can compose its own wording (or a translation) from fields instead of parsing the English sentence. One of api_free, volume_at_or_under_break_even, volume_needs_throughput, volume_api_cheaper, volume_self_host_cheaper, volume_exceeds_capacity, volume_only_at_higher_estimates, api_cheaper_any_volume, self_host_cheaper_above, self_host_above_utilization, break_even_and_required_throughput, busy_at_least_higher_estimates_only, busy_at_least_all_estimates, busy_at_least_between_estimates, published_minimum_settles, published_minimum_settles_at_volume. Several sentences exist per verdict, so verdict alone does not identify it. Kinds may be added: a client that does not know a kind should show headline",
    "headline_values": "Only the keys the sentence uses are present. Every value the headline quotes, rounded as the sentence quotes it; thousands and decimal separators are left to the client. Units: keys ending in _tps are tokens per second (floor_output_tps counts output tokens, the others input and output together); volume_m, break_even_m and usable_capacity_m_low/_high are million tokens a day; api_usd_per_m and self_hosted_usd_per_m_low/_high (no _high when the three scenarios cost the same) are USD per million tokens; keys ending in _percent are percent. Other keys: prefix (wide_estimate, estimate, your_throughput or null: the words that open the sentence), at_break_even (the volume equals the break-even volume: self-hosting is no cheaper), mix (default_3_1 or caller), required_tps_if_always_busy (null at 100% utilization), request_length (not_given: you did not describe your requests; within_benchmark: they fit the benchmark's 2,048 tokens in total), api_provider, gpu_name. Two optional parts add a sentence to any kind: floor_note (does_not_settle or does_not_settle_longer_requests, with floor_total_tps: a published minimum that does not decide) and comparison (the settled_alternative as quoted: gpus, gpu_name, usd_per_day in USD, break_even_m, busy_at_least_percent, evidence measured or published_minimum, and request_length with the same two values, or null when it does not apply: a measured value carries no length condition). The only text that comes from third-party pages is gpu_name (also in comparison) and api_provider: escape them before display. For a refusal the sentence is identified by reason, and its values are in detail",
    "settled_alternative": "Present when no published figure decides the verdict for the configuration the answer is about (self_host_needs_throughput) while published figures decide it for a dearer rented configuration (a measured value or a published minimum): the cheapest such configuration (card, number of GPUs, provider, tier, hourly and daily price with checked_at and source_url), its verdict, the confidence it rests on (measured or lower_bound) and its break-even volume. It is another, dearer setup, shown for comparison; it is not a recommendation, and it is never used in place of the configuration the answer is about. verdict is self_host_cheaper_above at your utilization, or self_host_above_utilization with busy_at_least_percent: for a measured value, the break-even utilization of the prudent scenario, which holds in all three; for a published minimum, a utilization at which the floor is enough (sufficient, not necessary). The verdict summarises the prudent case: asking for that configuration directly (gpu, gpu_count) can return self_host_needs_throughput with both ends of the range. An alternative that rests on a published minimum holds for requests of up to 2,048 tokens in total; none is pointed out when you describe longer requests. Absent when you impose a card (gpu) or give tokens_per_second; with gpu_count alone, only configurations of that size are considered",
    "status": "ok, or refused: we decline to give a number rather than an unreliable one. reason is one of model_closed_or_unsized, quantization_not_published, unknown_gpu, gpu_not_rented, weights_exceed_margin, no_rental_configuration, gpu_memory_unknown, no_api_price, no_api_offer_fits; detail says what is needed (for weights_exceed_margin: memory needed and available, and the smallest configuration that fits)",
    "threshold_m_tokens_per_day": "Break-even volume: daily cost of the GPU configuration divided by the API price per million tokens (blended 3:1, cheapest standard offer, promotions, unstable prices, off-peak prices without published hours and unverified prices far below those of the other providers excluded). Null when the API offer is free",
    "note": "Hardware rental only: the hourly price the provider publishes for the machine. It does not count the engineering to deploy and run the model, monitoring, redundancy, start-up time, or storage and network costs billed separately."
  }
}