# Best Practices Best practices and recommendations for using Lesan AI services. ## API Usage - Use async mode for audio files longer than 5 minutes - Implement proper error handling and retry logic (see examples below) - Respect [rate limits](/guides/rate-limits) and implement exponential backoff - Cache results when appropriate to reduce API calls - Use [webhooks](/guides/webhooks) instead of polling for async job notifications ## Error Handling Always check the HTTP status code and handle errors gracefully. Here is a reusable pattern for making API calls with proper error handling and retry logic: ```python import requests import time def lesan_request(method, endpoint, max_retries=3, **kwargs): """Make an API request with error handling and retry logic.""" url = f"https://asr.lesan.ai{endpoint}" headers = { "Authorization": "Bearer YOUR_API_KEY", **kwargs.pop("headers", {}) } for attempt in range(max_retries): try: response = method(url, headers=headers, **kwargs) if response.ok: return response.json() error = response.json().get("error", {}) # Retry on rate limits and server errors if response.status_code == 429: wait = error.get("retry_after", 2 ** attempt) print(f"Rate limited. Retrying in {wait}s...") time.sleep(wait) continue elif response.status_code >= 500: wait = 2 ** attempt print(f"Server error. Retrying in {wait}s...") time.sleep(wait) continue # Don't retry client errors raise Exception(f"{error.get('code')}: {error.get('message')}") except requests.ConnectionError: if attempt < max_retries - 1: time.sleep(2 ** attempt) continue raise raise Exception("Max retries exceeded") # Usage result = lesan_request( requests.post, "/transcribe", json={"audio_url": "https://example.com/audio.mp3", "language": "am", "mode": "sync"} ) print(result["text"]) ``` ```javascript async function lesanRequest(endpoint, options = {}, maxRetries = 3) { const url = `https://asr.lesan.ai${endpoint}`; const headers = { "Authorization": "Bearer YOUR_API_KEY", ...options.headers }; for (let attempt = 0; attempt < maxRetries; attempt++) { try { const response = await fetch(url, { ...options, headers }); if (response.ok) { return await response.json(); } const { error } = await response.json(); // Retry on rate limits and server errors if (response.status === 429) { const wait = error?.retry_after || 2 ** attempt; console.log(`Rate limited. Retrying in ${wait}s...`); await new Promise(r => setTimeout(r, wait * 1000)); continue; } else if (response.status >= 500) { const wait = 2 ** attempt; console.log(`Server error. Retrying in ${wait}s...`); await new Promise(r => setTimeout(r, wait * 1000)); continue; } // Don't retry client errors throw new Error(`${error.code}: ${error.message}`); } catch (err) { if (err.name === "TypeError" && attempt < maxRetries - 1) { await new Promise(r => setTimeout(r, 2 ** attempt * 1000)); continue; } throw err; } } throw new Error("Max retries exceeded"); } // Usage const result = await lesanRequest("/transcribe", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ audio_url: "https://example.com/audio.mp3", language: "am", mode: "sync" }) }); console.log(result.text); ``` See the [Error Codes](/guides/error-codes) reference for all error types and handling strategies. ## Audio Quality - Use high-quality audio files for better transcription accuracy - Record at 16kHz or higher sample rate — see [Audio Formats](/guides/audio-formats) - Use FLAC or WAV for best quality, MP3 for smaller file sizes - Minimize background noise when possible - For best results, use audio with clear speech and minimal overlapping speakers ## Security - Never expose API keys in client-side code — use publishable keys for browser apps - Store keys securely using environment variables - Rotate API keys regularly — especially when team members change - Use [restricted keys](/guides/authentication) with minimal scopes for each service - Enable IP whitelisting for server-side keys - Monitor API key usage for suspicious activity ## Performance - Use batch processing for multiple files instead of individual requests - Use [webhooks](/guides/webhooks) for async job notifications instead of polling - If polling, use 5-second intervals with exponential backoff - Optimize audio file sizes before uploading — downsample to 16kHz mono - Use [WebSocket streaming](/guides/streaming) for real-time use cases instead of repeated sync calls ## Production Checklist Before deploying to production, verify the following: - Error handling — All API calls have try/catch with retry logic for 429 and 500 errors - API keys — Using live keys (not test/dev), stored in environment variables - Rate limits — Monitoring usage via `X-RateLimit-Remaining` headers - Webhooks — Signature verification is implemented and tested - Timeouts — HTTP client timeouts are set (30s for sync, 10s for status checks) - Logging — Logging request IDs and error codes for debugging - Audio format — Files are in a [supported format](/guides/audio-formats) and under 500 MB - Scopes — API keys have only the minimum required scopes For more information, check out our [other guides](/guides) and the [API Reference](/api-reference).