# API Authentication & Usage Guide ## 🔐 Setting Up API Key in Hugging Face Spaces ### Step 1: Generate Secure API Key ```bash # Generate random API key (example methods) node -e "console.log('sk-' + require('crypto').randomBytes(32).toString('hex'))" # Or use Python python -c "import secrets; print('sk-' + secrets.token_hex(32))" ``` ### Step 2: Configure in HF Spaces 1. Navigate to your Space: `https://huggingface.co/spaces/your-username/space-name` 2. Click **"Settings"** tab 3. Click **"Variables"** section 4. Add this environment variable: | Variable | Value | Description | |----------|-------|-------------| | `API_KEY` | `sk-your-secure-key-here` | Single API key for authentication | ### Step 3: Test Authentication ```bash # Test without API key (should fail if authentication enabled) curl -X POST https://your-space.hf.space/screenshot \ -H "Content-Type: application/json" \ -d '{"url": "https://example.com"}' # Test with API key (should work) curl -X POST https://your-space.hf.space/screenshot \ -H "Authorization: Bearer your-api-key-here" \ -H "Content-Type: application/json" \ -d '{"url": "https://example.com"}' ``` ## 📊 Understanding Server Status Responses ### Normal Operation ```json { "status": "running", "system": { "cpuUsage": "25%" }, "queue": { "activeRequests": 1, "queuedRequests": 0 } } ``` ### Server Busy (CPU > 95%) ```json { "status": "busy", "error": "Server is currently overloaded", "cpuUsage": "96%", "queueLength": 3 } ``` ### Queue Full Response ```json { "status": "busy", "error": "Request queue timeout", "queueLength": 10 } ``` ## 🔄 Implementing Retry Logic ### JavaScript Retry Pattern ```javascript async function screenshotWithRetry(url, options = {}, maxRetries = 3) { for (let attempt = 1; attempt <= maxRetries; attempt++) { try { const response = await fetch('/screenshot', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': 'Bearer your-api-key' }, body: JSON.stringify({ url, ...options }) }); if (response.ok) { return await response.blob(); } if (response.status === 503) { const error = await response.json(); if (error.status === 'busy') { console.log(`Attempt ${attempt}: Server busy, retrying...`); await new Promise(resolve => setTimeout(resolve, 2000 * attempt)); continue; } } // Other errors, don't retry throw new Error(`API Error: ${response.status}`); } catch (error) { if (attempt === maxRetries) throw error; await new Promise(resolve => setTimeout(resolve, 1000 * attempt)); } } } ``` ### Python Retry Pattern ```python import time import requests from typing import Optional def screenshot_with_retry(url: str, api_key: str, max_retries: int = 3) -> Optional[bytes]: for attempt in range(1, max_retries + 1): try: response = requests.post( 'https://your-space.hf.space/screenshot', headers={'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json'}, json={'url': url}, timeout=30 ) if response.status_code == 200: return response.content if response.status_code == 503: error_data = response.json() if error_data.get('status') == 'busy': print(f"Attempt {attempt}: Server busy (CPU: {error_data.get('cpuUsage', 'N/A')})") time.sleep(2 * attempt) continue response.raise_for_status() except requests.RequestException as e: if attempt == max_retries: raise e time.sleep(attempt) return None ``` ## 🚨 Rate Limiting & Best Practices ### Rate Limit Headers The API returns rate limiting information: ``` X-RateLimit-Limit: 100 X-RateLimit-Remaining: 95 X-RateLimit-Reset: 1640995200 ``` ### Best Practices 1. **Implement exponential backoff** for retries 2. **Cache results** when possible 3. **Use appropriate image quality** (70-80% usually sufficient) 4. **Monitor your usage** via `/status` endpoint 5. **Handle queue timeouts** gracefully ### Production Usage Example ```javascript class ScreenshotAPI { constructor(apiKey, baseUrl) { this.apiKey = apiKey; this.baseUrl = baseUrl; this.requestCount = 0; this.resetTime = 0; } async screenshot(url, options = {}) { // Check rate limit if (this.requestCount >= 95 && Date.now() < this.resetTime) { throw new Error('Rate limit approached, waiting...'); } const response = await this.makeRequest('/screenshot', { method: 'POST', body: JSON.stringify({ url, ...options }) }); // Update rate limit tracking this.requestCount = parseInt(response.headers.get('X-RateLimit-Remaining') || '0'); this.resetTime = parseInt(response.headers.get('X-RateLimit-Reset') || '0') * 1000; return response; } async makeRequest(endpoint, options = {}) { return fetch(this.baseUrl + endpoint, { ...options, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${this.apiKey}`, ...options.headers } }); } } ``` ## 🔧 Troubleshooting ### Common Issues | Error | Cause | Solution | |-------|-------|----------| | `401 Unauthorized` | Missing API key | Add `Authorization: Bearer` header | | `403 Forbidden` | Invalid API key | Check key spelling/validity | | `503 Service Unavailable` | Server overloaded | Implement retry with delay | | `429 Too Many Requests` | Rate limit exceeded | Wait for reset time | ### Performance Optimization - Use smaller dimensions for faster processing - Lower quality settings for non-critical uses - Batch requests with appropriate delays - Monitor CPU usage via `/status`