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

# Authentication

> How to authenticate with the Ornn Data API using a Bearer API key, and which endpoints require one.

The Ornn Data API authenticates requests with an **API key** passed as a Bearer token, and not every endpoint requires one.

## The Authorization header

Send your key in the `Authorization` header on every request to a protected endpoint:

```
Authorization: Bearer YOUR_API_KEY
```

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://api.ornnai.com/api/gpu/H100%20SXM" \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```python Python theme={null}
  import requests

  resp = requests.get(
      "https://api.ornnai.com/api/gpu/H100 SXM",
      headers={"Authorization": "Bearer YOUR_API_KEY"},
  )
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch("https://api.ornnai.com/api/gpu/H100 SXM", {
    headers: { Authorization: "Bearer YOUR_API_KEY" },
  });
  ```

  ```php PHP theme={null}
  <?php
  $ch = curl_init("https://api.ornnai.com/api/gpu/" . rawurlencode("H100 SXM"));
  curl_setopt_array($ch, [
      CURLOPT_RETURNTRANSFER => true,
      CURLOPT_HTTPHEADER => ["Authorization: Bearer YOUR_API_KEY"],
  ]);
  $data = json_decode(curl_exec($ch), true);
  ```

  ```go Go theme={null}
  package main

  import (
  	"net/http"
  	"net/url"
  )

  func main() {
  	endpoint := "https://api.ornnai.com/api/gpu/" + url.PathEscape("H100 SXM")
  	req, _ := http.NewRequest("GET", endpoint, nil)
  	req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
  	resp, _ := http.DefaultClient.Do(req)
  	defer resp.Body.Close()
  }
  ```

  ```java Java theme={null}
  import java.net.URI;
  import java.net.http.HttpClient;
  import java.net.http.HttpRequest;
  import java.net.http.HttpResponse;

  HttpClient client = HttpClient.newHttpClient();
  HttpRequest request = HttpRequest.newBuilder(
          URI.create("https://api.ornnai.com/api/gpu/H100%20SXM"))
      .header("Authorization", "Bearer YOUR_API_KEY")
      .build();
  HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
  ```

  ```ruby Ruby theme={null}
  require "net/http"

  uri = URI("https://api.ornnai.com/api/gpu/H100%20SXM")
  req = Net::HTTP::Get.new(uri)
  req["Authorization"] = "Bearer YOUR_API_KEY"
  res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
  ```
</CodeGroup>

## Getting a key

API keys are created in the dashboard, not through the API. Sign in to [data.ornn.com](https://data.ornn.com), go to **Settings → API Keys**, and create one. See [Manage API keys](/docs/manage-api-keys) for details.

<Warning>
  Your full key (`sk_prem_...` on Trial/Premium, `sk_live_...` on Full) is shown **only once**, at creation. Store it somewhere safe. If you lose it, revoke it and create a new one. You cannot retrieve it later.
</Warning>

## Which endpoints need a key?

Ornn Data's access tiers are **Index** (free), **Premium** (\$500/month, or a 72-hour trial), and **Full** (custom). Index mirrors what you can already see on [index.ornn.com](https://index.ornn.com). A `sk_prem_` key unlocks every index family at daily grain with complete history, plus five forward curves (B300, GB200, and GB300 require Full). A `sk_live_` key unlocks hourly, those three enterprise forward curves, the B300 index, and neocloud site data. See [Access tiers](/docs/access-tiers) for the full matrix and [data.ornn.com/pricing](https://data.ornn.com/pricing) for prices.

### Granularity by tier

| Tier | Granularity | History |
| - | - | - |
| Free / anonymous | Daily | Trailing window only |
| **Premium** (`sk_prem_`) | **Daily only** | **Complete — no trailing window** |
| Full (`sk_live_`) | Daily and hourly | Complete |

Premium is a daily-grain tier at every range: the 1-year view, the all-time view and API-key access are all served at daily. A request for `granularity=hourly` or `auto` is answered at daily rather than refused, so existing integrations keep working — read the `granularity` field on the response to see what you were served. The endpoints that exist only to serve sub-daily data — `/api/gpu/{gpuName}/hourly`, `/api/gpu/{gpuName}/rolling-24h-average`, `/api/power/load`, and `/api/power/fuel-mix` — return `403` for a Premium key; all are included with a Full subscription. Daily history at `/api/gpu/{gpuName}/rolling-24h-average/history` remains Premium.

**Public GPU indices** (current price + **trailing 3 months** of history, no key): `H100 SXM`, `H200`, `B200`, `A100 SXM4`.

**Public token indices — OTPI** (current value + **trailing 1 month** of history, no key): `anthropic`, `openai`, `google`, `deepseek`.

| Access | Endpoints |
| - | - |
| **Public — GPU, 3-month window** | `/api/gpu/{gpuName}` (current price), `/api/gpu/{gpuName}/index-history`, `/api/h100-history` — **free-4 GPUs only** |
| **Public — GPU, trailing 7 settled days** | `/api/daily-index`, `/api/daily-index/all`, `/api/day-index` (deprecated), `/api/daily-index/{gpuName}/previous` — the settled daily index reaches back **7 days**, not 3 months, for every caller; the 3-month series is `/api/gpu/{gpuName}/index-history`. **Free-4 GPUs only** without a key |
| **Public — token (OTPI), 1-month window** | `/api/otpi` — **free-4 labs only** |
| **Public — no data windowing** | `/health`; catalogs `/api/gpu-types`, `/api/gpu-types-free`, `/api/token-types`, `/api/token-types-free`, `/api/memory-types`, `/api/llm-coding/products` |
| **Premium or Full key (`sk_prem_` / `sk_live_`)** | Every other index: `RTX PRO 6000 WS`, OTPI labs outside the free-4, memory prices and history, Workload Cost (`/api/workload`), LLM coding values and history, the forward curve (`/api/forward`; five GPUs on `sk_prem_`, B300 / GB200 / GB300 on `sk_live_` / Full only), Token Volume (`/api/token-volume`), Model Frontier (`/api/model-frontier`), Compute Buyers (`/api/compute-buyers`), daily Power Markets (`/api/power/markets`), volatility and volume analytics (`/api/gpu/{gpuName}/volume-metrics`, `/api/gpu-utilization`), and ranged GPU history. Premium is **daily grain only**. |
| **Full key only (`sk_live_`)** | GPU hourly routes (`/api/gpu/{gpuName}/hourly`), the current-value rolling 24-hour average (`/api/gpu/{gpuName}/rolling-24h-average`), hourly power operations (`/api/power/load`, `/api/power/fuel-mix`), neocloud site routes (`/api/neocloud/sites`, `/api/neocloud/map`, `/api/neocloud/sites/aggregate`), and the B300 index (`/api/gpu/B300/history-range`, `/volatility`, `/volume-metrics`). A Premium key returns `403`. Daily history at `/api/gpu/{gpuName}/rolling-24h-average/history` remains Premium. |

<Note>
  On the windowed endpoints, an anonymous request returns the free window and includes `"access": "public-3mo"` (GPU) or `"public-1mo"` (OTPI). Send your API key to reach the complete history — the response then returns `"access": "premium"` (Premium/`sk_prem_`) or `"access": "full"` (Full/`sk_live_`). A non-free GPU or a non-free OTPI lab is only served with a key (otherwise `401`). A `startDate` earlier than the free window is **clamped** to the window rather than refused: the GPU routes answer `200` with `"access": "public-3mo"`, and `/api/otpi` answers `200` with `"access": "public-1mo"` as long as `endDate` still falls inside or after its window. `/api/otpi` refuses with `401` only when the whole `startDate`–`endDate` range predates the free window. The Workload Cost Index and LLM coding analytics do not have a free window: `/api/workload`, `/api/llm-coding/index`, and `/api/llm-coding/history` require a key on every request.
</Note>

<Tip>
  To discover the free-vs-paid split at runtime — for example to render a pricing table — pair the full catalog with its `-free` companion: `/api/gpu-types` with [`/api/gpu-types-free`](/docs/api-reference/reference/list-free-tier-gpu-models), and [`/api/token-types`](/docs/api-reference/token-prices/list-tracked-otpi-labs) with [`/api/token-types-free`](/docs/api-reference/token-prices/list-free-tier-otpi-labs). The `-free` routes return the same list regardless of caller tier.
</Tip>

<Note>
  Public index and catalog routes that use the public limiter are limited to 60 requests/minute per IP. Because the limiter runs before optional authentication, sending a valid API key does not switch those requests to a separate per-key limit. See [Rate limits](/docs/rate-limits).
</Note>

## Authentication errors

If the key is missing, malformed, or invalid, you get a `401`:

```json theme={null}
{
  "error": "Unauthorized",
  "message": "API key required. Use Authorization: Bearer YOUR_API_KEY"
}
```

```json theme={null}
{
  "error": "Unauthorized",
  "message": "Invalid API key"
}
```

A revoked key returns `{"error": "Unauthorized", "message": "API key is inactive"}`. See [Errors & status codes](/docs/errors) for the full list.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.