> ## 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.

# Boas Práticas

> Recomendações para usar a API de forma eficiente e segura

## Segurança

<CardGroup cols={2}>
  <Card title="Proteja sua Chave de API" icon="key">
    * Nunca exponha em código-fonte público
    * Use variáveis de ambiente
    * Não inclua em logs
  </Card>

  <Card title="Use HTTPS" icon="lock">
    * Sempre use HTTPS para requisições
    * Verifique certificados SSL
    * Não aceite certificados inválidos
  </Card>

  <Card title="Defina Expiração" icon="clock">
    * Configure datas de expiração para chaves
    * Rotacione chaves periodicamente
    * Revogue chaves comprometidas imediatamente
  </Card>

  <Card title="Princípio do Menor Privilégio" icon="shield">
    * Crie chaves com permissões mínimas necessárias
    * Use chaves diferentes para ambientes diferentes
    * Delete chaves não utilizadas
  </Card>
</CardGroup>

## Tratamento de Erros

<Steps>
  <Step title="Sempre Verifique o Status HTTP">
    Não assuma sucesso - verifique o código de status em toda requisição.

    ```javascript theme={null}
    if (!response.ok) {
      const error = await response.json();
      console.error('Erro:', error.error.message);
    }
    ```
  </Step>

  <Step title="Implemente Retry Logic">
    Para erros temporários (5xx, 429), implemente retry com backoff exponencial.

    ```javascript theme={null}
    const delay = Math.pow(2, attempt) * 1000; // 1s, 2s, 4s, 8s...
    await new Promise(r => setTimeout(r, delay));
    ```
  </Step>

  <Step title="Use Timeouts Apropriados">
    Configure timeouts para evitar requisições penduradas.

    ```javascript theme={null}
    const controller = new AbortController();
    const timeout = setTimeout(() => controller.abort(), 30000);

    const response = await fetch(url, {
      signal: controller.signal
    });
    ```
  </Step>

  <Step title="Trate Erros Específicos">
    Implemente handlers para diferentes tipos de erro.

    ```javascript theme={null}
    switch (response.status) {
      case 401: handleAuthError(); break;
      case 404: handleNotFound(); break;
      case 429: handleRateLimit(); break;
    }
    ```
  </Step>
</Steps>

## Performance

<AccordionGroup>
  <Accordion title="Evite Requisições Desnecessárias" icon="bolt">
    * Implemente cache local quando apropriado
    * Use filtros para buscar apenas dados necessários
    * Agrupe operações quando possível
  </Accordion>

  <Accordion title="Use Paginação" icon="list">
    * Sempre use `limit` e `offset` para listas grandes
    * Não tente buscar todos os dados de uma vez
    * Processe dados em lotes

    ```javascript theme={null}
    let offset = 0;
    const limit = 50;

    while (true) {
      const response = await fetch(
        `${url}?limit=${limit}&offset=${offset}`
      );
      const data = await response.json();

      if (data.length === 0) break;

      processData(data);
      offset += limit;
    }
    ```
  </Accordion>

  <Accordion title="Respeite Rate Limits" icon="gauge">
    * Monitore headers de rate limit
    * Implemente throttling do lado do cliente
    * Use filas para operações em massa
  </Accordion>

  <Accordion title="Monitore Tempos de Resposta" icon="clock">
    * Registre latências das requisições
    * Configure alertas para degradação
    * Use métricas para identificar problemas
  </Accordion>
</AccordionGroup>

## Webhooks

<CardGroup cols={2}>
  <Card title="Responda Rápido" icon="gauge-high">
    Retorne 200 rapidamente e processe em background. Webhooks têm timeout.
  </Card>

  <Card title="Idempotência" icon="clone">
    Processe eventos de forma idempotente - o mesmo evento pode ser enviado mais de uma vez.
  </Card>

  <Card title="Valide Payloads" icon="check-double">
    Sempre valide a estrutura do payload antes de processar.
  </Card>

  <Card title="Log Eventos" icon="file-lines">
    Registre todos os eventos recebidos para debugging e auditoria.
  </Card>
</CardGroup>

## Exemplo de Cliente Robusto

<CodeGroup>
  ```javascript JavaScript theme={null}
  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));
    }

    // Métodos de conveniência
    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}`);
    }
  }

  // Uso
  const client = new LeavoClient(process.env.LEAVO_API_KEY);
  const leads = await client.getLeads({ limit: 50 });
  ```

  ```python Python theme={null}
  import os
  import time
  import requests
  from typing import Optional, Dict, Any

  class LeavoClient:
      def __init__(self, api_key: str):
          self.api_key = api_key
          self.base_url = 'https://api.leavo.ai'
          self.session = requests.Session()
          self.session.headers.update({
              'Authorization': f'Bearer {api_key}',
              'Content-Type': 'application/json'
          })

      def request(
          self,
          method: str,
          path: str,
          data: Optional[Dict] = None,
          retries: int = 3
      ) -> Any:
          for attempt in range(retries):
              try:
                  response = self.session.request(
                      method,
                      f'{self.base_url}{path}',
                      json=data,
                      timeout=30
                  )

                  if response.status_code == 429:
                      retry_after = int(response.headers.get('Retry-After', 60))
                      time.sleep(retry_after)
                      continue

                  if response.status_code >= 500:
                      time.sleep(2 ** attempt)
                      continue

                  response.raise_for_status()

                  return response.json() if response.status_code != 204 else None

              except requests.RequestException as e:
                  if attempt == retries - 1:
                      raise
                  time.sleep(2 ** attempt)

      # Métodos de conveniência
      def get_leads(self, **params):
          return self.request('GET', '/backend/leads', params=params)

      def create_lead(self, data: Dict):
          return self.request('POST', '/backend/leads', data=data)

      def update_lead(self, lead_id: str, data: Dict):
          return self.request('PUT', f'/backend/leads/{lead_id}', data=data)

      def delete_lead(self, lead_id: str):
          return self.request('DELETE', f'/backend/leads/{lead_id}')


  # Uso
  client = LeavoClient(os.environ['LEAVO_API_KEY'])
  leads = client.get_leads(limit=50)
  ```
</CodeGroup>
