# Authentication

> Where the API key goes on RPC, WebSocket and gRPC requests, and the errors a bad key returns.

Source: https://docs.constant-k.com/get-started/authentication/

Every constant-k request must carry your API key. The key identifies your account and your plan.

## Where to find your key

The **Endpoints** section of [My Account](https://www.constant-k.com/my-account/) shows your API key and your ready-made endpoint URLs. Kaldera and Turbo Kaldera use the same key as Solana RPC. On Nexus, ShredPrism connection details are on the same page.

## Where the key goes

| Protocol                           | Query parameter                 | Header                              |
| :--------------------------------- | :------------------------------ | :---------------------------------- |
| Solana RPC over HTTP               | `api-key` or `api_key`          | `x-api-key`, `api-key` or `x-token` |
| WebSocket                          | `api-key` in the connection URL | —                                   |
| Kaldera, Turbo Kaldera, ShredPrism | —                               | `x-token` metadata                  |

A header keeps the key out of URLs, so it is less likely to reach logs and error messages. The query string suits tools that accept only a URL, such as wallets, Jupiter and most trading bots.

## HTTP examples

**cURL**

```bash
# Key in the query string
curl "https://rpc-newyork.constant-k.com/?api-key=YOUR_API_KEY" \
  -X POST -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"getSlot"}'

# Key in a header
curl "https://rpc-newyork.constant-k.com/" \
  -X POST -H "Content-Type: application/json" \
  -H "x-api-key: YOUR_API_KEY" \
  -d '{"jsonrpc":"2.0","id":1,"method":"getSlot"}'
```

**TypeScript**

```ts
import { createSolanaRpc } from "@solana/kit";

const rpc = createSolanaRpc("https://rpc-newyork.constant-k.com/", {
  headers: { "x-api-key": process.env.CK_API_KEY! },
});

console.log(await rpc.getSlot().send());
```

**Python**

```python
import os
import requests

response = requests.post(
    "https://rpc-newyork.constant-k.com/",
    headers={"x-api-key": os.environ["CK_API_KEY"]},
    json={"jsonrpc": "2.0", "id": 1, "method": "getSlot"},
    timeout=10,
)
print(response.json())
```

## WebSocket example

```text
wss://ws-newyork.constant-k.com:1337/ws?api-key=YOUR_API_KEY
```

See [WebSockets](https://docs.constant-k.com/rpc/websockets/).

## gRPC examples

gRPC clients send the key as the `x-token` metadata header.

**TypeScript**

```ts
import Client from "@triton-one/yellowstone-grpc";

// The second argument is sent as the x-token header
const client = new Client(
  "https://kaldera-newyork.constant-k.com",
  process.env.CK_API_KEY,
  undefined,
);
await client.connect();
```

**Rust**

```rust
let client = GeyserGrpcClient::build_from_shared("https://kaldera-newyork.constant-k.com")?
    .x_token(Some(std::env::var("CK_API_KEY")?))?
    .tls_config(ClientTlsConfig::new().with_native_roots())?
    .connect()
    .await?;
```

**grpcurl**

```bash
grpcurl -H "x-token: YOUR_API_KEY" \
  -import-path ./proto -proto geyser.proto \
  -d '{"slots": {"tip": {}}}' \
  kaldera-newyork.constant-k.com:443 geyser.Geyser/Subscribe
```

The [Kaldera quickstart](https://docs.constant-k.com/kaldera/quickstart/) has complete, runnable examples.

## Authentication errors

| Protocol      | Missing key                                                         | Invalid key                           |
| :------------ | :------------------------------------------------------------------ | :------------------------------------ |
| HTTP JSON-RPC | HTTP `401`, message `Missing API key`                               | HTTP `403`, message `Invalid API key` |
| WebSocket     | The server closes the connection right after it opens               | Same                                  |
| gRPC          | Status `UNAUTHENTICATED` (16), message `Missing or Invalid API Key` | Same                                  |

The HTTP responses carry a JSON-RPC error body:

```json
{ "jsonrpc": "2.0", "error": { "code": -32600, "message": "Invalid API key" }, "id": null }
```

Many SDKs show only the HTTP status. `@solana/kit` throws `HTTP error (403): Forbidden`. The Rust `RpcClient` reports `403 Forbidden` together with the full request URL.

> **Errors can leak your key:** When the key is in the query string, some clients print the full URL, key included, in error messages. A scrubbed log, or the key in a header, keeps it out of them.

## Key rotation

The [My Account](https://www.constant-k.com/my-account/) page re-rolls the key, once every 24 hours. The old key stops working immediately, so every client, bot and config file needs the new one at the same time.

## Key handling

* The key belongs on the server. Anyone who can read it can use your plan's limits.
* An environment variable or a secret manager holds it, not source code.
* Browser code, mobile apps and public repositories expose it. Browser traffic goes through your own backend instead.
* A key that may have reached someone else is replaced by a re-roll.
