> ## Documentation Index
> Fetch the complete documentation index at: https://mathematicalcompany.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Authentication

> Set up your Horizon API key to use the SDK.

Horizon requires an API key to use. You can get one by signing up at [api.mathematicalcompany.com](https://api.mathematicalcompany.com), or programmatically via the SDK.

## Setup

### Option A: Website (Manual)

<Steps>
  <Step title="Get your API key">
    Sign up at [api.mathematicalcompany.com](https://api.mathematicalcompany.com) and copy your API key.
    Keys start with `hz_sdk_`.
  </Step>

  <Step title="Set the environment variable">
    Add this to your shell profile (`~/.zshrc`, `~/.bashrc`, etc.):

    ```bash theme={null}
    export HORIZON_API_KEY="hz_sdk_abc123..."
    ```

    Then reload your shell or run `source ~/.zshrc`.
  </Step>

  <Step title="Run your strategy">
    ```bash theme={null}
    python my_strategy.py
    ```

    That's it. The SDK validates your key once at startup and caches the result locally. There is **zero latency impact** on trading.
  </Step>
</Steps>

### Option B: Programmatic (Agentic)

Create an account and generate an SDK key entirely from the command line or through an AI agent. No browser required.

<Steps>
  <Step title="Install the SDK">
    ```bash theme={null}
    pip install horizon-sdk
    # or
    uv pip install horizon-sdk
    ```
  </Step>

  <Step title="Run setup">
    Pass your password via the `HORIZON_PASSWORD` environment variable to avoid shell history exposure:

    ```bash theme={null}
    HORIZON_PASSWORD="your-password" python -c "
    from horizon.auth import setup
    result = setup('you@example.com', name='Your Name')
    print(result)
    "
    ```

    This will:

    1. Try to log in (if you already have an account)
    2. Sign up if the account does not exist
    3. Generate a new SDK key
    4. Save the encrypted key to `~/.horizon/credentials.json`

    On success you will see:

    ```json theme={null}
    {
      "status": "ok",
      "prefix": "hz_sdk_a1b2c3d",
      "credentials_path": "/home/you/.horizon/credentials.json",
      "message": "SDK key saved (encrypted) to ..."
    }
    ```

    <Warning>
      If Supabase email confirmation is enabled, you will see `"status": "confirmation_required"`. Check your email and confirm before running setup again.
    </Warning>
  </Step>

  <Step title="Run your strategy">
    The engine auto-loads the key from `~/.horizon/credentials.json`:

    ```bash theme={null}
    python my_strategy.py
    ```

    Or set the env var explicitly:

    ```bash theme={null}
    export HORIZON_API_KEY="hz_sdk_..."
    ```
  </Step>
</Steps>

#### MCP / AI Agent Setup

AI agents using the [MCP server](/integrations/mcp-server) or [OpenClaw skill](/integrations/openclaw) can call the auth tools directly:

| Tool      | Action       | Description                                     |
| --------- | ------------ | ----------------------------------------------- |
| `account` | `setup`      | Create account and generate SDK key (full flow) |
| `account` | `login`      | Login to existing account and generate new key  |
| `account` | `key_status` | Check if credentials are configured             |

The agent asks the user for their email, sets `HORIZON_PASSWORD`, and calls `account(action="setup", params="{\"email\": \"...\"}")`. The key is saved encrypted to disk and never returned in full in tool responses (only the prefix is shown).

#### Python API

```python theme={null}
from horizon.auth import (
    setup,           # Full flow: signup/login + key gen + save
    login,           # Login only
    signup,          # Signup only
    generate_sdk_key,  # Generate hz_sdk_ key
    hash_api_key,    # SHA-256 hash
    create_sdk_key,  # Insert key into Supabase
    save_credentials,  # Save encrypted to disk
    load_credentials,  # Load from disk
    resolve_password,  # Resolve from env var or argument
)
```

#### Security

* **Passwords**: Always use the `HORIZON_PASSWORD` env var instead of passing passwords as CLI arguments. CLI arguments are visible in shell history and process listings.
* **Key storage**: Credentials are encrypted at rest using a machine-derived key (hostname + username). The plaintext key is never written to disk.
* **Key exposure**: Tool responses only include the key prefix, never the full key.
* **Rate limiting**: Client-side rate limiting caps auth attempts to 5 per 60 seconds.

## How It Works

1. **Startup only** - validation happens once when `Engine` is created (inside `hz.run()`). After that, no network calls are made during trading.
2. **Local cache** - a successful validation is cached at `~/.horizon/license.json` for 72 hours. The raw key is never stored, only a SHA-256 hash.
3. **Offline grace period** - if the network is unavailable but a valid cache exists for your key, the SDK allows startup. No internet dependency during cached periods.
4. **Compiled in Rust** - the validation logic is in the compiled binary, not in bypassable Python code.

## Configuration

There are two ways to provide your API key:

### Environment Variable (Recommended)

```bash theme={null}
export HORIZON_API_KEY="hz_sdk_abc123..."
```

This is the recommended approach. Set it once in your shell profile and forget about it.

### Explicit Parameter

You can pass the key directly in code - useful for notebooks, testing, or when you don't want to set environment variables.

**With `hz.run()`:**

```python theme={null}
hz.run(
    name="my_strategy",
    api_key="hz_sdk_abc123...",
    markets=["test-market"],
    pipeline=[fair_value, quoter],
)
```

**With `Engine()` directly:**

```python theme={null}
from horizon import Engine, RiskConfig

engine = Engine(RiskConfig(), api_key="hz_sdk_abc123...")
```

The explicit parameter takes priority over the environment variable.

### Resolution Order

| Priority | Source                                                        |
| -------- | ------------------------------------------------------------- |
| 1        | `api_key` param in `hz.run()` / `api_key` param in `Engine()` |
| 2        | `HORIZON_API_KEY` environment variable                        |
| 3        | `~/.horizon/credentials.json` (saved by programmatic setup)   |

## Error Messages

If the key is missing:

```
RuntimeError: auth error: No Horizon API key provided. Set HORIZON_API_KEY
or pass api_key to hz.run(). Get your key at api.mathematicalcompany.com
```

If the key is invalid or expired:

```
RuntimeError: auth error: Invalid or expired API key. Check your key at
api.mathematicalcompany.com
```

If there's a network error and no cached validation:

```
RuntimeError: auth error: Could not validate API key (network error) and no
cached validation found. Check your internet connection.
```

## Cache Location

The license cache is stored at:

```
~/.horizon/license.json
```

To force re-validation (e.g., after upgrading your plan), delete this file:

```bash theme={null}
rm ~/.horizon/license.json
```

## Using with Docker

Pass the key as an environment variable:

```dockerfile theme={null}
ENV HORIZON_API_KEY="hz_sdk_abc123..."
```

Or at runtime:

```bash theme={null}
docker run -e HORIZON_API_KEY="hz_sdk_..." my-strategy
```
