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

# Authentication

> How to authenticate with the Tornado API

## API Keys

All API requests require authentication using an API key. Include your key in the `x-api-key` header with every request.

```bash theme={null}
curl -X GET "https://api.tornadoapi.io/usage" \
  -H "x-api-key: sk_your_api_key"
```

## Key Format

API keys follow this format:

* Prefix: `sk_` (secret key)
* Length: 32 characters total
* Example: `sk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6`

<Warning>
  Keep your API key secret! Never expose it in client-side code or public repositories.
</Warning>

## Request Headers

| Header         | Required | Description                                 |
| -------------- | -------- | ------------------------------------------- |
| `x-api-key`    | Yes      | Your API key for authentication             |
| `Content-Type` | For POST | Set to `application/json` for JSON payloads |

## Error Responses

### Missing API Key

```json theme={null}
{
  "error": "Missing x-api-key header"
}
```

**Status Code:** `401 Unauthorized`

### Invalid API Key

```json theme={null}
{
  "error": "Invalid API Key"
}
```

**Status Code:** `401 Unauthorized`

## Code Examples

<CodeGroup>
  ```python Python theme={null}
  import requests

  headers = {
      "x-api-key": "sk_your_api_key",
      "Content-Type": "application/json"
  }

  response = requests.post(
      "https://api.tornadoapi.io/jobs",
      headers=headers,
      json={"url": "https://youtube.com/watch?v=..."}
  )
  ```

  ```javascript Node.js theme={null}
  const axios = require('axios');

  const client = axios.create({
    baseURL: 'https://api.tornadoapi.io',
    headers: {
      'x-api-key': 'sk_your_api_key',
      'Content-Type': 'application/json'
    }
  });

  const response = await client.post('/jobs', {
    url: 'https://youtube.com/watch?v=...'
  });
  ```

  ```go Go theme={null}
  package main

  import (
      "bytes"
      "net/http"
  )

  func main() {
      client := &http.Client{}

      body := []byte(`{"url": "https://youtube.com/watch?v=..."}`)
      req, _ := http.NewRequest("POST", "https://api.tornadoapi.io/jobs", bytes.NewBuffer(body))

      req.Header.Set("x-api-key", "sk_your_api_key")
      req.Header.Set("Content-Type", "application/json")

      resp, _ := client.Do(req)
      defer resp.Body.Close()
  }
  ```
</CodeGroup>

## Rate Limits

Currently, there are no strict rate limits. However, we recommend:

* Maximum 500 concurrent jobs per API key
* Polling interval of 2-5 seconds for job status

<Note>
  Contact us if you need higher limits for your use case.
</Note>

## Security Best Practices

<AccordionGroup>
  <Accordion icon="lock" title="Environment Variables">
    Store your API key in environment variables, not in code:

    ```bash theme={null}
    export TORNADO_API_KEY="sk_your_api_key"
    ```
  </Accordion>

  <Accordion icon="server" title="Server-Side Only">
    Always make API calls from your backend server, never from client-side JavaScript.
  </Accordion>

  <Accordion icon="rotate" title="Key Rotation">
    If you suspect your key is compromised, contact us immediately for a new key.
  </Accordion>
</AccordionGroup>
