> ## Documentation Index
> Fetch the complete documentation index at: https://docs.compute-desk.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrating from v1

> What each v1 endpoint becomes in v2, and the four behaviour changes to check

v2 serves the same market data as v1 through one consistent surface. This
page maps every v1 endpoint onto its v2 replacement and lists the behaviour changes worth checking
before you switch.

<Note>
  **v1 is not going away yet, and nothing you have built breaks.** Move when it suits you, and move
  one endpoint at a time — the two can be called side by side with the same token.
</Note>

## 1. Swap your API key for an access token

v2 does not accept legacy `gpi_…` API keys. Ask us for an access token
([david@compute-index.com](mailto:david@compute-index.com)) and send it as:

```
Authorization: Bearer YOUR_TOKEN
```

Your data access carries across unchanged — you get the same data types and the same history depth
you have today. We enable v2 on the token at the same time.

Two practical differences from the key you use now:

* **It goes in the `Authorization` header**, not `X-API-Key`. v2 does not read `X-API-Key` at all.
* **It works for both versions.** You do not need to run two credentials during the move; the same
  token calls v1 and v2, so you can migrate endpoint by endpoint.

<Warning>
  Tokens are long-lived and grant access to your licensed data. Keep one in an environment variable
  or a secrets manager, never in source control, and ask us to rotate it if it is ever exposed.
</Warning>

## 2. Find your endpoints

Every v2 data type answers the same four questions, so the mapping is mostly mechanical:
`current` → `latest`, `available` / `reference` → `metadata`.

### Rental prices

| v1                   | v2                                                                                        |
| -------------------- | ----------------------------------------------------------------------------------------- |
| `/v1/prices/current` | `/v2/gpu/rental/prices/latest`                                                            |
| `/v1/prices/as-of`   | `/v2/gpu/rental/prices/as-of`                                                             |
| `/v1/prices/history` | `/v2/gpu/rental/prices/history`                                                           |
| `/v1/prices/lowest`  | `/v2/gpu/rental/prices/latest?sort_by=price_usd_per_gpu_hour&sort_order=asc&page_size=10` |

`/lowest` has no direct replacement because it no longer needs one — sorting is available on every
endpoint, so "the cheapest ten" is an ordinary query.

### Indices

| v1                           | v2                                                          |
| ---------------------------- | ----------------------------------------------------------- |
| `/v1/txn-index/current`      | `/v2/gpu/rental/indexes/latest?id=rental-…-1y-us-daily`     |
| `/v1/txn-index/as-of`        | `/v2/gpu/rental/indexes/as-of?id=rental-…-1y-us-daily`      |
| `/v1/txn-index/history`      | `/v2/gpu/rental/indexes/history?id=rental-…-1y-us-daily`    |
| `/v1/custom-index/current`   | `/v2/gpu/rental/indexes/latest?id=rental-…-1y-us-intraday`  |
| `/v1/custom-index/as-of`     | `/v2/gpu/rental/indexes/as-of?id=rental-…-1y-us-intraday`   |
| `/v1/custom-index/history`   | `/v2/gpu/rental/indexes/history?id=rental-…-1y-us-intraday` |
| `/v1/custom-index/available` | `/v2/gpu/rental/indexes/metadata`                           |
| `/v1/custom-index/reference` | `/v2/gpu/rental/indexes/metadata`                           |
| `/v1/info-index/*`           | no v2 replacement                                           |

**Every index is served from one place, and a request names one index by `id`.** Where v1 took a
scope — `gpu_family=hopper&region_group=US`, or `gpu_group=h100` — v2 takes the id of that series:
`rental-hopper-1y-us-daily`, `rental-h100-1y-us-daily`. The 30-minute series v1 called custom
indices end in `-intraday` instead, so v1's custom `h100-us` is v2's `rental-h100-1y-us-intraday`.
The id scheme is explained on [Indexes](/pricing/indexes), and
[`/metadata`](/pricing/endpoint/gpu-rental-indexes-metadata) lists the ids your token holds.

Two fields are renamed on every row: `index_value` is `value`, and the point's date or instant is
`timestamp` on both daily and intraday rows. A row's `type` — `daily` or `intraday` — says which
it carries. `txn_count` and the settled-only `index_type=raw` leg are not carried across.

### Transactions

| v1                            | v2                                               |
| ----------------------------- | ------------------------------------------------ |
| `/v1/txn-aggregate`           | `/v2/gpu/rental/transactions/aggregated/history` |
| `/v1/txn-aggregate/analytics` | `/v2/gpu/rental/transactions/aggregated/history` |

Both v1 endpoints become one. The bulk variant existed to return more rows at once; in v2 you page
through the full result set instead, so a single endpoint covers both uses.

### Reference lists

In v1 these were four global lists. In v2 each data type publishes its own vocabulary through
`/metadata`, so the values you get back are the ones **that type** actually accepts.

| v1                   | v2                                                                            |
| -------------------- | ----------------------------------------------------------------------------- |
| `/v1/gpus`           | `/v2/gpu/rental/prices/metadata` — the `gpus` list                            |
| `/v1/contract-types` | `/v2/gpu/rental/transactions/aggregated/metadata` — the `contract_types` list |
| `/v1/vendors`        | No direct equivalent yet                                                      |
| `/v1/regions`        | No direct equivalent yet                                                      |

<Note>
  **If you rely on `/v1/vendors` or `/v1/regions`, keep using them for now.** v2 accepts `vendor`
  and `region` as filters and sorts by them, but does not yet publish either list through
  `/metadata`. Tell us if you need them and we will prioritise it.
</Note>

### New in v2

No v1 equivalent exists for these:

| v2                          | What it is                               |
| --------------------------- | ---------------------------------------- |
| `/v2/gpu/hardware/prices/…` | Prices to buy GPU hardware outright      |
| `/v2/llm/token/prices/…`    | LLM inference prices, per million tokens |

## 3. Check these four behaviour changes

Everything else is a rename. These four will change what your code receives.

<AccordionGroup>
  <Accordion title="Paging works differently — no page numbers, no total count" icon="list-ol">
    v1 used `offset` and told you the `total_count`. v2 gives you a **link to the next page**
    instead: read `meta.next` and call it, and stop when it is `null`.

    ```python theme={null}
    url = "https://data-api.compute-index.com/v2/gpu/rental/prices/latest?gpu_search=H100"
    rows = []
    while url:
        body = requests.get(url, headers=headers, timeout=30).json()
        rows += body["data"]
        nxt = body["meta"]["next"]
        url = nxt["url"] if nxt else None
    ```

    **Send nothing alongside the next link** — it already carries your filters, dates and sort
    order. Adding a parameter returns an error rather than being quietly ignored.

    There is no total count. `meta.has_more` tells you whether another page exists, which is the
    question a paging loop actually asks.
  </Accordion>

  <Accordion title="/history returns what CHANGED, not everything in force" icon="clock-rotate-left">
    This is the change most likely to surprise you.

    v1's `/history` returned every record that was still in force at any point during your window —
    so a price set months ago and never changed came back in every window since. Two adjacent
    windows returned nearly the same rows.

    v2's `/history` returns records that **changed inside the window**. Ask for yesterday and you
    get yesterday's changes.

    * Charting a series over time? `/history` — unchanged in spirit, far fewer rows.
    * Need the price on a particular day? Use `/as-of`, which is the endpoint for that question.
  </Accordion>

  <Accordion title="Date ranges exclude the end instant" icon="calendar">
    `start` is included and `end` is not, so consecutive ranges join up without returning anything
    twice — you can pull a year month by month and not deduplicate.

    Plain dates still behave as you would expect: `?start=2026-06-01&end=2026-06-01` is that whole
    day.
  </Accordion>

  <Accordion title="Errors carry a code to branch on" icon="triangle-exclamation">
    v1 returned `{"detail": "…"}`. v2 adds a stable `code` alongside the human-readable message:

    ```json theme={null}
    { "status": 403, "code": "insufficient_entitlement", "detail": "…" }
    ```

    Match on `code`. `detail` is written for people and its wording may change.
  </Accordion>
</AccordionGroup>

## 4. Field names are consistent now

The same thing is spelled the same way everywhere. If a field meant one thing on one v1 endpoint and
something slightly different on another, v2 gives it one name and one meaning.

The practical effect: check the field names in a v2 response once per data type, rather than per
endpoint. Each type's page lists them in full, and `/metadata` tells you what you can filter on.

## Need a hand?

Tell us which endpoints you use and we will map them for you —
[david@compute-index.com](mailto:david@compute-index.com).
