---
title: 'Authentication & Credentials'
description: 'Configure Kalshi credentials and use Neural auth helpers for signed requests.'
---

Neural’s auth stack centralizes everything needed to sign requests against the Kalshi trading API. It keeps secret handling inside a dedicated module so the rest of the SDK can trust a consistent interface.

## Credential Sources

The SDK resolves credentials in a predictable order:

1. Environment variables (recommended for CI/CD)
   - `KALSHI_API_KEY_ID`
   - `KALSHI_PRIVATE_KEY_BASE64` *(base64-encoded RSA key material)*
   - Optional overrides: `KALSHI_API_KEY_PATH`, `KALSHI_PRIVATE_KEY_PATH`, `KALSHI_ENV`
2. Files in `secrets/` (developer default)
   - `secrets/kalshi_api_key_id.txt`
   - `secrets/kalshi_private_key.pem`

The helper functions in `neural.auth.env` encapsulate those lookups and raise informative errors when nothing is configured. That keeps the failure mode obvious during local development and prevents silent `None` values from flowing into the trading layer.

```python
from neural.auth.env import get_api_key_id, get_private_key_material

api_key = get_api_key_id()
private_key = get_private_key_material()
```

> **Tip:** use `utils/kalshi_secrets.py` to populate environment variables in interactive shells.

## Signing Requests

`KalshiSigner` produces the signature headers required by Kalshi’s REST, WebSocket, and FIX endpoints. It accepts raw PEM bytes and lazily loads an RSA private key so the same object can be reused by multiple clients.

```python
from neural.auth.signers.kalshi import KalshiSigner
from neural.auth.env import get_api_key_id, get_private_key_material

signer = KalshiSigner(
    api_key_id=get_api_key_id(),
    private_key_pem=get_private_key_material(),
)
headers = signer.headers("GET", "/trade-api/v2/portfolio")
```

Each call signs the tuple `<timestamp><METHOD><path>` and returns the three Kalshi headers (`KALSHI-ACCESS-KEY`, `KALSHI-ACCESS-TIMESTAMP`, `KALSHI-ACCESS-SIGNATURE`).

## Authenticated REST Helpers

### `AuthClient`

`AuthClient` is a thin, retry-aware wrapper around `requests.Session`. Pass it a signer and call `get`, `post`, or `delete` with Kalshi trade-api paths.

```python
from neural.auth.client import AuthClient
from neural.auth.signers.kalshi import KalshiSigner
from neural.auth.env import get_api_key_id, get_private_key_material

signer = KalshiSigner(get_api_key_id(), get_private_key_material())
client = AuthClient(signer)

markets = client.get("/trade-api/v2/markets", params={"limit": 25})
print(markets["markets"][0]["ticker"])
```

Key behaviors:

- Automatically rebuilds auth headers after a `401` to keep sessions fresh.
- Retries common transient statuses (`429`, `5xx`) with exponential backoff.
- Returns JSON for successful responses and raises informative `requests.HTTPError`s otherwise.

### `KalshiHTTPClient`

For higher-level integrations, `neural.auth.http_client.KalshiHTTPClient` layers the signer on top of full REST URL construction and adds pagination helpers used by the historical data module.

```python
from neural.auth.http_client import KalshiHTTPClient

http = KalshiHTTPClient()
portfolio = http.get("/portfolio")
trades = http.get_trades(ticker="KXNFLGAME-25SEP22DETBAL-BAL", limit=500)
```

It automatically prefixes `/trade-api/v2`, applies rate-limit retries, and exposes convenience methods like `get_trades` for the documented historical endpoints.

## Environments

Kalshi currently exposes production endpoints only. Passing any value other than `prod/production/live` to `get_base_url()` raises a helpful error so misconfigured demo credentials fail fast.

```python
from neural.auth.env import get_base_url

api_host = get_base_url()  # -> https://api.elections.kalshi.com
```

That guard keeps the rest of the SDK from silently calling non-existent hosts.

## Troubleshooting

- **Missing credentials** – confirm the env vars are exported or the `secrets/` files exist. The raised `FileNotFoundError` includes which path was attempted.
- **Invalid signature** – verify the private key matches the API key ID and is unencrypted. Password-protected PEMs are not supported.
- **Clock drift** – signatures include a millisecond timestamp; keep system clocks in sync (e.g., via `ntp`).

Once this module is configured, higher layers—data collection, strategies, and trading—can be instantiated without worrying about secrets or signature logic.
