> ## 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. A `sk_live_` key unlocks hourly, real-time, 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, hourly and real-time | 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 two endpoints that exist only to serve sub-daily data, `/api/gpu/{gpuName}/hourly` and `/api/gpu/{gpuName}/realtime`, return `403` for a premium key; both are included with a full subscription.

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

**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/daily-index`, `/api/daily-index/all`, `/api/day-index` (deprecated), `/api/daily-index/{gpuName}/previous`, `/api/gpu/{gpuName}/index-history`, `/api/h100-history` — **free-5 GPUs only**                       |
| **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, analytics (volatility, utilization), and ranged GPU history. Premium is **daily grain only**. |
| **Full key only (`sk_live_`)**                    | `/api/gpu/{gpuName}/hourly`, `/api/gpu/{gpuName}/realtime`, and neocloud site routes (`/api/neocloud/sites`, `/api/neocloud/map`, `/api/neocloud/sites/aggregate`). A Premium key returns `403`.                                                             |

<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 `startDate` earlier than the free window, a non-free GPU, or a non-free OTPI lab is only served with a key (otherwise `401`). 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.
