CH·02CLI reference

gpu market history

Show a GPU's price and availability over time

Show a GPU's price and availability over time

Synopsis

Prints the price and stock curve for one GPU model, optionally narrowed to a region and a capacity class. Leave both off and the series merges every region and both classes — the aggregator view, and usually the one you want.

Requires an API key with the market:read scope. The *current* price is public; the *curve* is not, so this endpoint is authenticated and rate-limited per key.

Reading the output

h100_sxm · us-west · secure · every node size
15-minute buckets · 2026-09-01T00:00:00Z → 2026-09-01T01:00:00Z · 4 buckets · 1 sold out · 1 with no data collected

BUCKET                PRICE/GPU-HR                AVAILABLE
2026-09-01T00:00:00Z  $3.85 (from an 8-GPU node)  24
2026-09-01T00:15:00Z  $4.20                       3
2026-09-01T00:30:00Z  $4.20                       0 (sold out)
2026-09-01T00:45:00Z  no data                     no data

0 (sold out) and no data are not the same thing, and this is the most important thing to understand about the series.

CellJSONMeaning
0 (sold out)"available_count": 0Sold out — 0 available. We sampled that bucket and nothing was on the market. A real, observed stockout you can act on.
no data"available_count": nullNo data collected for this window. We did not sample that bucket — a failed poll, a skipped cycle, an incident on our side. It is not a stockout.

A missing bucket is a statement about *our sampling*, never about *supply*. Do not treat a run of no data as a shortage, and do not draw a line across it: the points either side are not known to be connected. The header line tells you how many buckets in the window are gaps, so you can judge the coverage of a series before you trust its shape.

A price with no available capacity is normal and not a contradiction: a listing can carry a price while nothing behind it is obtainable.

Derived per-GPU rates

PRICE/GPU-HR is always a per-GPU hourly rate. When that rate was divided out of a whole-node price, it is labelled:

$3.85 (from an 8-GPU node)

The qualifier is there because a bare per-GPU figure implies you can rent one GPU at that price, which for whole-node capacity is not true — you would be renting the node. A rate with no parenthetical came from single-GPU capacity and needs no qualification.

Window limits

The window caps below are enforced by the API. The CLI checks them first, so an over-wide window fails immediately instead of costing you a request.

--bucketScopeMaximum window
15m--region and --capacity-class set90 days
15meither one left off31 days
1dany365 days (the full retention window)

The 31-day limit exists because an unscoped 15-minute series has to scan every region and class in every bucket. It costs you nothing you cannot get another way — there are two cheap ways past it, and the error names both:

  • scope the series with --region and --capacity-class, which buys the full 90 days at the same resolution; or
  • ask for --bucket 1d, which re-aggregates the same data server-side and reaches back a year.
With no --from/--to you get the last 7 days. History is retained for 365 days; nothing older than that is stored.
gpu market history [flags]

Examples

# The last week of H100 SXM, every region, both classes and node sizes
gpu market history --gpu-model h100_sxm

# A specific month, scoped — scoping is what buys you the 90-day raw window
gpu market history --gpu-model h100_sxm --region us-west --capacity-class secure \
    --from 2026-08-01 --to 2026-09-01

# A year at daily resolution, machine-readable
gpu market history --gpu-model h100_sxm --bucket 1d --from 2025-09-01 -o json

# Count the buckets we actually sampled (null = not sampled, so filter it out
# rather than treating it as a zero)
gpu market history --gpu-model h100_sxm -o json |
  jq '[.points[] | select(.available_count != null)] | length'

# The cheapest per-GPU rate we ever recorded in the window
gpu market history --gpu-model h100_sxm -o json |
  jq '[.points[].price_per_gpu_hour | select(. != null)] | min'

GPU model

--gpu-model takes a model id from gpu gpu-types listh100_sxm, rtx_4090, a100_80gb. Punctuation and case don't matter, so RTX-4090 and rtx 4090 both resolve to rtx_4090, and the JSON echoes the canonical id back so you can see which series you were served.

An id we don't list is refused, with the nearest models named:

$ gpu market history --gpu-model h100_80gb
Error: gpu_model "h100_80gb" is not a GPU model we list, so it has no market
history; did you mean h100_nvl, h100_pcie, h100_sxm? See GET /v1/gpu-types for
the models we carry (validation_failed)

This is the same rule as node size below, for the same reason. h100_80gb is a reasonable thing to type — it's how the part is marketed — but we split that generation by interconnect because the three SKUs are differently priced. Before this was refused it returned a full series of nulls, which is exactly what a real model we hadn't sampled looks like: a typo was indistinguishable from an outage on our side, and it read as a broken chart rather than a wrong id.

A model we do list but haven't sampled in your window is still a 200 with a null-filled series. That is the honest answer and the distinction this surface is built on — see the note on null in the examples above.

Node size

A 1-GPU box and an 8-GPU node are different products at different per-GPU rates, so the series keeps them apart. --cluster-size 8 charts 8-GPU nodes only; omitting it merges every shape, which is the default and what "what does this GPU cost" means without further qualification.

# Only 8-GPU nodes
gpu market history --gpu-model h100_sxm --cluster-size 8

Accepted sizes are 1, 2, 4, 8, 10, 16 — the shapes the catalog is offered in. Anything else is refused rather than answered with an empty series, because an empty series is indistinguishable from a genuine gap and this surface exists so "no data" and "nothing to have data about" are never the same answer.

available_cluster_sizes in the JSON reports the shapes that actually have rows for this model, region, class and window — narrower than the accepted list, and what a picker should offer. An empty array means we looked and found none.

There is no history from before the per-size split. Node size became a dimension of the table on 2026-09-10; buckets recorded earlier are the merged series and carry no per-size breakdown. They are served by the default (merged) view and are deliberately absent from a size-filtered one — inventing a breakdown that was never sampled would be a false claim about the past. So a --cluster-size query starts at that date, while the merged view is continuous across it.

Options

      --bucket string           Resolution: 15m (up to 90 days scoped, 31 days unscoped) or 1d (up to 365 days) (default "15m")
      --capacity-class string   Narrow the series to one capacity class: secure or community (omit to merge both)
      --cluster-size int        Narrow the series to one node shape, e.g. 8 for 8-GPU nodes (omit to merge every size; a 1-GPU box and an 8-GPU node are different products at different per-GPU rates)
      --from string             Start of the window, RFC3339 or YYYY-MM-DD (default: 7 days before --to)
      --gpu-model string        GPU model to chart, e.g. h100_sxm (required)
  -h, --help                    help for history
      --region string           Canonical region to narrow the series to, e.g. us-west (omit to merge every region)
      --to string               End of the window, RFC3339 or YYYY-MM-DD (default: now)

Options inherited from parent commands

      --api-base string   API base URL (override with GPUAI_API_BASE env) (default "https://api.gpu.ai/v1")
      --debug             Enable debug logging to stderr
  -o, --output string     Output format: table|json (default table on TTY, json otherwise)

SEE ALSO

  • gpu market - Look at how a GPU's price and availability have moved over time
  • gpu watch create - Get alerted when the market moves, instead of going to look

← The gpu CLI