Documentation Index
Fetch the complete documentation index at: https://docs.leavo.ai/llms.txt
Use this file to discover all available pages before exploring further.
Security
Protect Your API Key
- Never expose in public source code
- Use environment variables
- Don’t include in logs
Use HTTPS
- Always use HTTPS for requests
- Verify SSL certificates
- Don’t accept invalid certificates
Set Expiration
- Configure expiration dates for keys
- Rotate keys periodically
- Revoke compromised keys immediately
Least Privilege Principle
- Create keys with minimum necessary permissions
- Use different keys for different environments
- Delete unused keys
Error Handling
Always Check HTTP Status
Don’t assume success - check the status code in every request.if (!response.ok) {
const error = await response.json();
console.error('Error:', error.error.message);
}
Implement Retry Logic
For temporary errors (5xx, 429), implement retry with exponential backoff.const delay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s, 8s...
await new Promise(r => setTimeout(r, delay));
Use Appropriate Timeouts
Configure timeouts to avoid hanging requests.const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 30000);
const response = await fetch(url, {
signal: controller.signal
});
Handle Specific Errors
Implement handlers for different error types.switch (response.status) {
case 401: handleAuthError(); break;
case 404: handleNotFound(); break;
case 429: handleRateLimit(); break;
}
Avoid Unnecessary Requests
- Implement local cache when appropriate
- Use filters to fetch only necessary data
- Batch operations when possible
- Monitor rate limit headers
- Implement client-side throttling
- Use queues for bulk operations
- Record request latencies
- Set up alerts for degradation
- Use metrics to identify issues
Webhooks
Respond Quickly
Return 200 quickly and process in background. Webhooks have timeout.
Idempotency
Process events idempotently - the same event may be sent more than once.
Validate Payloads
Always validate the payload structure before processing.
Log Events
Record all received events for debugging and auditing.
Robust Client Example
class LeavoClient {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseUrl = 'https://api.leavo.ai';
}
async request(method, path, data = null, retries = 3) {
for (let attempt = 0; attempt < retries; attempt++) {
try {
const response = await fetch(`${this.baseUrl}${path}`, {
method,
headers: {
'Authorization': `Bearer ${this.apiKey}`,
'Content-Type': 'application/json'
},
body: data ? JSON.stringify(data) : null,
signal: AbortSignal.timeout(30000)
});
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After') || 60;
await this.sleep(retryAfter * 1000);
continue;
}
if (response.status >= 500) {
await this.sleep(Math.pow(2, attempt) * 1000);
continue;
}
if (!response.ok) {
const error = await response.json();
throw new Error(error.error?.message || 'Request failed');
}
return response.status === 204 ? null : response.json();
} catch (error) {
if (attempt === retries - 1) throw error;
await this.sleep(Math.pow(2, attempt) * 1000);
}
}
}
sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// Convenience methods
getLeads(params = {}) {
const query = new URLSearchParams(params).toString();
return this.request('GET', `/backend/leads?${query}`);
}
createLead(data) {
return this.request('POST', '/backend/leads', data);
}
updateLead(id, data) {
return this.request('PUT', `/backend/leads/${id}`, data);
}
deleteLead(id) {
return this.request('DELETE', `/backend/leads/${id}`);
}
}
// Usage
const client = new LeavoClient(process.env.LEAVO_API_KEY);
const leads = await client.getLeads({ limit: 50 });