# Authentication

Most API endpoints are public and don't require authentication. When bearer token auth is enabled on the server, write endpoints (order submission, cancellation) require an API key.

## Public Endpoints

All `GET` endpoints are public and do not require authentication, including:

* `/api/v1/markets`
* `/api/v1/orderbook/{marketId}`
* `/api/v1/trades/{marketId}`
* `/api/v1/stats/{marketId}`
* `/api/v1/platform/stats`
* `/api/v1/quick-markets/{asset}`
* `/api/v1/resolution/{marketId}`
* `/api/v1/stream` (WebSocket)

## Bearer Token Authentication

When enabled, write endpoints require an `Authorization` header with a signed bearer token.

### Token Format

Tokens use Ed25519 signatures and have the form:

```
base64url(payload).base64url(signature)
```

The payload is a JSON object:

```json
{
  "kid": "your-key-id",
  "ts": 1735689000,
  "n": "random-32-char-hex-nonce"
}
```

| Field | Type   | Description                                       |
| ----- | ------ | ------------------------------------------------- |
| `kid` | string | API key ID (matches your registered key)          |
| `ts`  | int64  | Unix timestamp when token was created             |
| `n`   | string | Random 32-character hex nonce (replay prevention) |

Tokens are valid for 5 minutes from the `ts` timestamp.

{% hint style="info" %}
Ensure your system clock is accurate when generating tokens. Tokens older than 5 minutes will be rejected.
{% endhint %}

### Making Authenticated Requests

Include the token in the `Authorization` header:

{% code title="curl example" %}

```bash
curl -X POST https://api.turbinefi.com/api/v1/orders \
  -H "Authorization: Bearer <payload>.<signature>" \
  -H "Content-Type: application/json" \
  -d '{ ... }'
```

{% endcode %}

## Registering an API Key

Register for API credentials by proving wallet ownership with an Ethereum signature.

POST to:

```
POST /api/v1/api-keys
```

This endpoint does not require bearer authentication — it uses wallet signature verification instead.

{% stepper %}
{% step %}

### Request: Register API Key

Request body (JSON):

```json
{
  "address": "0xYourWalletAddress",
  "signature": "0x...",
  "name": "my-trading-bot"
}
```

| Field       | Type    | Required | Description                    |
| ----------- | ------- | -------- | ------------------------------ |
| `address`   | address | Yes      | Your Ethereum wallet address   |
| `signature` | string  | Yes      | Signature of the message below |
| `name`      | string  | No       | Friendly name for the key      |

The message to sign:

```
Register API key for Turbine: 0xYourWalletAddress
```

Sign this message using a standard Ethereum personal sign (`eth_sign` or `personal_sign`).
{% endstep %}

{% step %}

### Response: API Key Created

Successful response example:

```json
{
  "success": true,
  "api_key_id": "abc123def456...",
  "api_private_key": "deadbeef...",
  "message": "API key created successfully. Save your private key - it cannot be retrieved later!"
}
```

| Field             | Type   | Description                                           |
| ----------------- | ------ | ----------------------------------------------------- |
| `success`         | bool   | Whether registration succeeded                        |
| `api_key_id`      | string | Your key ID (used in `kid` field of tokens)           |
| `api_private_key` | string | Ed25519 private key hex (save this — shown only once) |
| `message`         | string | Status message                                        |
| {% endstep %}     |        |                                                       |

{% step %}

### Generating Tokens (Client-side)

Use your `api_key_id` and `api_private_key` to generate bearer tokens.

Python example:

{% code title="generate token (python)" %}

```python
import json
import time
import base64
import secrets
from nacl.signing import SigningKey

# Your credentials from registration
key_id = "abc123def456..."
private_key_hex = "deadbeef..."

# Create payload
payload = {
    "kid": key_id,
    "ts": int(time.time()),
    "n": secrets.token_hex(16)
}

# Sign with Ed25519
payload_bytes = json.dumps(payload).encode()
signing_key = SigningKey(bytes.fromhex(private_key_hex))
signature = signing_key.sign(payload_bytes).signature

# Encode token
token = (
    base64.urlsafe_b64encode(payload_bytes).rstrip(b"=").decode()
    + "."
    + base64.urlsafe_b64encode(signature).rstrip(b"=").decode()
)

# Use in requests
headers = {"Authorization": f"Bearer {token}"}
```

{% endcode %}

Use the generated token in the `Authorization` header when calling write endpoints.
{% endstep %}
{% endstepper %}

### Error Responses

<details>

<summary>Error responses for token/auth related failures</summary>

| Status | Error                          | Description                                |
| ------ | ------------------------------ | ------------------------------------------ |
| 401    | `missing authorization header` | No `Authorization` header provided         |
| 401    | `invalid authorization format` | Must be `Bearer <token>`                   |
| 401    | `invalid token format`         | Token is malformed                         |
| 401    | `token expired`                | Token `ts` is older than 5 minutes         |
| 401    | `API key not found`            | The `kid` doesn't match any registered key |
| 401    | `API key is inactive`          | Key has been revoked                       |
| 401    | `API key has expired`          | Key's expiration time has passed           |
| 401    | `invalid signature`            | Ed25519 signature verification failed      |

</details>
