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

# API Keys

> Generate and manage API keys to securely integrate HITL.sh with your applications and workflows

# API Keys

API keys are your secure credentials for integrating HITL.sh with your applications, workflows, and third-party tools. They authenticate your requests and ensure only authorized systems can interact with your loops and data.

## Understanding API Keys

API keys in HITL.sh serve as your application's identity and provide secure access to:

* **Loop Management**: Create, read, update, and delete loops
* **Request Operations**: Submit requests and retrieve responses
* **Loop Members**: Add and remove reviewers from loops
* **Webhook Configuration**: Set up event notifications
* **Request Feedback**: Add feedback to completed requests

<Warning>
  Keep your API keys secure and never expose them in client-side code or public repositories. Treat them like passwords.
</Warning>

## Generating Your First API Key

<Steps>
  <Step title="Log In to Dashboard">
    Visit [my.hitl.sh](https://my.hitl.sh) and log in to your account.
  </Step>

  <Step title="Navigate to API Keys">
    Go to Settings → API Keys from the main navigation menu.
  </Step>

  <Step title="Create New API Key">
    Click the "Create New API Key" button to generate a new key.
  </Step>

  <Step title="Copy and Store Securely">
    Copy the generated API key immediately and store it securely in environment variables. The key is only shown once for security reasons.
  </Step>
</Steps>

<Warning>
  API keys are shown only once when created. Store them immediately in a secure location like environment variables or a secrets manager.
</Warning>

## API Key Management

### Viewing Active Keys

Your dashboard shows all active API keys with their:

* **Name**: Descriptive label for easy identification
* **Permissions**: Access level granted to the key
* **Created Date**: When the key was generated
* **Last Used**: Most recent activity timestamp
* **Status**: Active, suspended, or expired

### API Key Permissions

API keys have specific permissions based on your account and plan:

<AccordionGroup>
  <Accordion title="Loop Operations">
    * Create, read, update, and delete loops
    * Manage loop members (add/remove reviewers)
    * View loop statistics and activity
  </Accordion>

  <Accordion title="Request Operations">
    * Create requests in loops you own
    * View and cancel your requests
    * Add feedback to completed requests
    * Access request history and responses
  </Accordion>

  <Accordion title="Webhook Configuration">
    * Set up webhook endpoints for real-time notifications
    * Configure webhook events and filters
    * View webhook delivery logs and status
  </Accordion>
</AccordionGroup>

### Security Best Practices

<CardGroup cols={2}>
  <Card title="Environment Variables" icon="lock">
    Store API keys in environment variables, never hardcode them in your source code.
  </Card>

  <Card title="Key Rotation" icon="refresh">
    Regularly rotate your API keys to minimize the impact of potential compromises.
  </Card>

  <Card title="Scope Permissions" icon="shield">
    Grant only the minimum permissions necessary for each integration.
  </Card>

  <Card title="Monitor Usage" icon="eye">
    Regularly review API key usage to detect unauthorized access.
  </Card>
</CardGroup>

## Using API Keys

### Authentication Header

Include your API key in the `Authorization` header of all API requests:

```bash theme={null}
Authorization: Bearer YOUR_API_KEY_HERE
```

### Testing Your API Key

Use the test endpoint to verify your API key is working correctly:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET 'https://api.hitl.sh/v1/test' \
    -H 'Authorization: Bearer YOUR_API_KEY'
  ```

  ```python Python theme={null}
  import requests

  headers = {
      'Authorization': 'Bearer YOUR_API_KEY'
  }

  response = requests.get('https://api.hitl.sh/v1/test', headers=headers)
  data = response.json()

  if data["error"] == False:
      print("✅ API key is valid!")
      print(f"Rate limit: {data['data']['rate_limit']['remaining']}/{data['data']['rate_limit']['limit']}")
  else:
      print("❌ API key validation failed")
  ```

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

  const headers = {
      'Authorization': 'Bearer YOUR_API_KEY'
  };

  async function testApiKey() {
      try {
          const response = await axios.get('https://api.hitl.sh/v1/test', { headers });
          if (!response.data.error) {
              console.log('✅ API key is valid!');
              console.log(`Rate limit: ${response.data.data.rate_limit.remaining}/${response.data.data.rate_limit.limit}`);
          }
      } catch (error) {
          console.error('❌ API key validation failed:', error.response?.data);
      }
  }

  testApiKey();
  ```
</CodeGroup>

**Expected Response:**

```json theme={null}
{
  "error": false,
  "msg": "API key is valid",
  "data": {
    "api_key_id": "65f1234567890abcdef12349",
    "user_id": "65f1234567890abcdef12346",
    "email": "user@example.com", 
    "account_status": "active",
    "rate_limit": {
      "limit": 100,
      "remaining": 95,
      "reset_at": "2024-03-15T15:00:00Z"
    },
    "permissions": ["loops:read", "loops:write", "requests:read", "requests:write"]
  }
}
```

## Rate Limits

API keys have usage limits to ensure fair usage:

<Card title="Current Rate Limits" icon="clock">
  * **100 requests per hour** per API key
  * Rate limits reset at the **top of each hour** (e.g., 1:00 PM, 2:00 PM, not rolling 60 minutes)
  * Rate limit information included in response headers
  * `X-RateLimit-Reset` header shows the exact UTC timestamp when the limit resets
</Card>

**Rate Limit Headers:**

```
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 85  
X-RateLimit-Reset: 1642237200
```

### Handling Rate Limits

```python theme={null}
import time
import requests

def make_api_request_with_retry(url, headers, data=None, max_retries=3):
    for attempt in range(max_retries):
        try:
            if data:
                response = requests.post(url, headers=headers, json=data)
            else:
                response = requests.get(url, headers=headers)
            
            if response.status_code == 429:
                # Rate limited - wait and retry
                retry_after = int(response.headers.get('Retry-After', 60))
                print(f"Rate limited. Waiting {retry_after} seconds...")
                time.sleep(retry_after)
                continue
                
            return response
            
        except Exception as e:
            if attempt == max_retries - 1:
                raise e
            time.sleep(2 ** attempt)  # Exponential backoff
    
    return None
```

## Integration Examples

### Creating Your First Loop

```python theme={null}
import requests

api_key = "YOUR_API_KEY"
headers = {
    "Authorization": f"Bearer {api_key}",
    "Content-Type": "application/json"
}

# Create a new loop
response = requests.post(
    "https://api.hitl.sh/v1/api/loops",
    headers=headers,
    json={
        "name": "Content Moderation Loop",
        "description": "Review user-generated content for compliance"
    }
)

if response.status_code == 200:
    loop_data = response.json()
    print(f"✅ Loop created: {loop_data['data']['id']}")
```

### Submitting a Request

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

const apiKey = 'YOUR_API_KEY';
const loopId = 'your_loop_id';

const headers = {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
};

async function submitRequest() {
    try {
        const response = await axios.post(
            `https://api.hitl.sh/v1/api/loops/${loopId}/requests`,
            {
                processing_type: 'time-sensitive',
                type: 'markdown',
                priority: 'medium',
                request_text: 'Please review this content for appropriateness.',
                response_type: 'single_select',
                response_config: {
                    options: [
                        { value: 'approve', label: 'Approve' },
                        { value: 'reject', label: 'Reject' }
                    ],
                    required: true
                },
                timeout_seconds: 3600,
                platform: 'api'
            },
            { headers }
        );
        
        console.log('✅ Request submitted:', response.data.data.id);
        return response.data.data;
    } catch (error) {
        console.error('❌ Error submitting request:', error.response?.data);
    }
}

submitRequest();
```

## Troubleshooting

### Common Issues

<AccordionGroup>
  <Accordion title="401 Unauthorized - Invalid API Key">
    **Symptoms:** `{"error": true, "msg": "Invalid authorization token"}`

    **Solutions:**

    * Verify the API key is copied correctly without extra spaces
    * Check if the key has been revoked in your dashboard
    * Ensure you're using the Bearer format: `Authorization: Bearer YOUR_API_KEY`
    * Confirm you're not including extra characters or line breaks
  </Accordion>

  <Accordion title="403 Forbidden - Insufficient Permissions">
    **Symptoms:** `{"error": true, "msg": "Access denied to this resource"}`

    **Solutions:**

    * Verify your API key has the required permissions
    * Check if you're trying to access resources you don't own
    * Ensure your account has the necessary features enabled
  </Accordion>

  <Accordion title="429 Rate Limited">
    **Symptoms:** `{"error": true, "msg": "API rate limit exceeded"}`

    **Solutions:**

    * Wait for the rate limit to reset (check `X-RateLimit-Reset` header)
    * Implement exponential backoff in your retry logic
    * Use the `/test` endpoint to check your current rate limit status
    * Consider batching requests to optimize usage
  </Accordion>

  <Accordion title="Network or Connection Issues">
    **Symptoms:** Connection timeouts or network errors

    **Solutions:**

    * Verify you can reach `api.hitl.sh` from your network
    * Check if you're behind a corporate firewall blocking the API
    * Ensure you're using HTTPS (not HTTP) for all requests
    * Try from a different network to isolate connectivity issues
  </Accordion>
</AccordionGroup>

### Debug Authentication

Use this debug script to troubleshoot API key issues:

```python theme={null}
import requests

def debug_api_key(api_key):
    """Debug API key authentication issues"""
    headers = {"Authorization": f"Bearer {api_key}"}
    
    try:
        response = requests.get("https://api.hitl.sh/v1/test", headers=headers)
        
        print(f"Status Code: {response.status_code}")
        print(f"Response: {response.json()}")
        
        if response.status_code == 200:
            data = response.json()["data"]
            print("\n🔍 API Key Debug Info:")
            print(f"   Account: {data['email']}")
            print(f"   Status: {data['account_status']}")
            print(f"   Rate Limit: {data['rate_limit']['remaining']}/{data['rate_limit']['limit']}")
            print(f"   Permissions: {', '.join(data['permissions'])}")
        
    except Exception as e:
        print(f"❌ Error: {e}")

# Test your API key
debug_api_key("YOUR_API_KEY_HERE")
```

## Next Steps

Now that you have your API key set up, you're ready to:

<CardGroup cols={2}>
  <Card title="Test Your API Key" icon="vial" href="/api-reference/test-api-key">
    Verify your API key is working with the test endpoint.
  </Card>

  <Card title="Create Your First Loop" icon="plus" href="/api-reference/loops/create-loop">
    Set up a human-in-the-loop workflow using the API.
  </Card>

  <Card title="Submit Your First Request" icon="paper-plane" href="/api-reference/requests/create-request">
    Send content for human review and get responses.
  </Card>

  <Card title="API Reference" icon="book" href="/api-reference/introduction">
    Explore all available endpoints and integration options.
  </Card>
</CardGroup>
