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

# Tratamento de Erros

> Como lidar com erros e exceções na Wapizap API

# Tratamento de Erros

Este guia explica como a Wapizap API reporta erros e como tratá-los corretamente em sua aplicação.

## Formato de Resposta de Erro

Todas as respostas de erro seguem este formato:

```json theme={null}
{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "Descrição legível do erro",
    "details": {}
  }
}
```

| Campo           | Tipo    | Descrição                              |
| --------------- | ------- | -------------------------------------- |
| `success`       | boolean | Sempre `false` para erros              |
| `error.code`    | string  | Código único do erro (use para lógica) |
| `error.message` | string  | Mensagem legível (use para logs/debug) |
| `error.details` | object  | Informações adicionais (opcional)      |

***

## Códigos HTTP

| Código | Significado         | Quando Ocorre                        |
| ------ | ------------------- | ------------------------------------ |
| `400`  | Bad Request         | Dados inválidos ou faltando          |
| `401`  | Unauthorized        | Token ausente ou inválido            |
| `403`  | Forbidden           | Sem permissão para a ação            |
| `404`  | Not Found           | Recurso não existe                   |
| `409`  | Conflict            | Conflito (ex: nome duplicado)        |
| `422`  | Unprocessable       | Dados válidos mas não processáveis   |
| `429`  | Too Many Requests   | Rate limit excedido                  |
| `500`  | Internal Error      | Erro interno do servidor             |
| `503`  | Service Unavailable | Serviço temporariamente indisponível |

***

## Erros Comuns

### Autenticação (401)

```json theme={null}
{
  "success": false,
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Invalid API key provided"
  }
}
```

**Solução:** Verifique se o header `Authorization: Bearer SEU_TOKEN` está correto.

***

### Instância Não Encontrada (404)

```json theme={null}
{
  "success": false,
  "error": {
    "code": "INSTANCE_NOT_FOUND",
    "message": "Instance 'minha-instancia' not found"
  }
}
```

**Solução:** Verifique se o `instanceId` está correto e se a instância existe.

***

### Instância Desconectada (422)

```json theme={null}
{
  "success": false,
  "error": {
    "code": "INSTANCE_NOT_CONNECTED",
    "message": "Instance is not connected to WhatsApp"
  }
}
```

**Solução:** Reconecte a instância usando o endpoint de conexão.

***

### Número Inválido (400)

```json theme={null}
{
  "success": false,
  "error": {
    "code": "INVALID_NUMBER",
    "message": "The phone number is not registered on WhatsApp",
    "details": {
      "number": "5511999999999"
    }
  }
}
```

**Solução:** Use `/contacts/check` para validar números antes de enviar.

***

### Rate Limit (429)

```json theme={null}
{
  "success": false,
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Too many requests. Please retry after 60 seconds.",
    "details": {
      "retryAfter": 60,
      "limit": 30,
      "remaining": 0
    }
  }
}
```

**Solução:** Aguarde o tempo indicado em `retryAfter` e implemente exponential backoff.

***

### Mídia Muito Grande (400)

```json theme={null}
{
  "success": false,
  "error": {
    "code": "MEDIA_TOO_LARGE",
    "message": "Media file exceeds maximum size",
    "details": {
      "maxSize": "16MB",
      "receivedSize": "25MB"
    }
  }
}
```

**Solução:** Reduza o tamanho do arquivo antes de enviar.

***

## Tratamento em Código

### JavaScript/TypeScript

```javascript theme={null}
async function sendMessage(instanceId, to, text) {
  try {
    const response = await fetch('https://api.wapizap.com/api/v2/messages', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${API_KEY}`
      },
      body: JSON.stringify({ instanceId, to, type: 'text', text })
    });

    const data = await response.json();

    if (!data.success) {
      // Tratar erro baseado no código
      switch (data.error.code) {
        case 'INSTANCE_NOT_CONNECTED':
          await reconnectInstance(instanceId);
          return sendMessage(instanceId, to, text); // Retry

        case 'INVALID_NUMBER':
          console.error(`Número inválido: ${to}`);
          return null;

        case 'RATE_LIMIT_EXCEEDED':
          const retryAfter = data.error.details?.retryAfter || 60;
          await sleep(retryAfter * 1000);
          return sendMessage(instanceId, to, text); // Retry

        default:
          throw new Error(data.error.message);
      }
    }

    return data.data;

  } catch (error) {
    console.error('Erro ao enviar mensagem:', error);
    throw error;
  }
}

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}
```

### Python

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

def send_message(instance_id, to, text):
    try:
        response = requests.post(
            'https://api.wapizap.com/api/v2/messages',
            headers={
                'Content-Type': 'application/json',
                'Authorization': f'Bearer {API_KEY}'
            },
            json={
                'instanceId': instance_id,
                'to': to,
                'type': 'text',
                'text': text
            }
        )

        data = response.json()

        if not data.get('success'):
            error_code = data.get('error', {}).get('code')

            if error_code == 'INSTANCE_NOT_CONNECTED':
                reconnect_instance(instance_id)
                return send_message(instance_id, to, text)  # Retry

            elif error_code == 'INVALID_NUMBER':
                print(f'Número inválido: {to}')
                return None

            elif error_code == 'RATE_LIMIT_EXCEEDED':
                retry_after = data.get('error', {}).get('details', {}).get('retryAfter', 60)
                time.sleep(retry_after)
                return send_message(instance_id, to, text)  # Retry

            else:
                raise Exception(data.get('error', {}).get('message'))

        return data.get('data')

    except Exception as e:
        print(f'Erro ao enviar mensagem: {e}')
        raise
```

***

## Exponential Backoff

Para erros temporários (429, 500, 503), implemente exponential backoff:

```javascript theme={null}
async function fetchWithRetry(url, options, maxRetries = 3) {
  let lastError;

  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);
      const data = await response.json();

      if (data.success) {
        return data;
      }

      // Erros que não devem ser retentados
      const nonRetryable = ['UNAUTHORIZED', 'INVALID_NUMBER', 'NOT_FOUND'];
      if (nonRetryable.includes(data.error?.code)) {
        throw new Error(data.error.message);
      }

      // Rate limit - usar tempo específico
      if (data.error?.code === 'RATE_LIMIT_EXCEEDED') {
        const waitTime = data.error.details?.retryAfter || 60;
        await sleep(waitTime * 1000);
        continue;
      }

      lastError = new Error(data.error?.message);

    } catch (error) {
      lastError = error;
    }

    // Exponential backoff: 1s, 2s, 4s, 8s...
    const waitTime = Math.pow(2, attempt) * 1000;
    console.log(`Tentativa ${attempt + 1} falhou. Aguardando ${waitTime}ms...`);
    await sleep(waitTime);
  }

  throw lastError;
}
```

***

## Códigos de Erro por Categoria

### Autenticação

| Código                     | Descrição                 |
| -------------------------- | ------------------------- |
| `UNAUTHORIZED`             | Token inválido ou ausente |
| `TOKEN_EXPIRED`            | Token expirado            |
| `INSUFFICIENT_PERMISSIONS` | Sem permissão para a ação |

### Instâncias

| Código                    | Descrição                |
| ------------------------- | ------------------------ |
| `INSTANCE_NOT_FOUND`      | Instância não existe     |
| `INSTANCE_NOT_CONNECTED`  | Instância desconectada   |
| `INSTANCE_ALREADY_EXISTS` | Nome já em uso           |
| `INSTANCE_LIMIT_EXCEEDED` | Limite do plano atingido |
| `QR_CODE_EXPIRED`         | QR code expirou          |

### Mensagens

| Código               | Descrição                   |
| -------------------- | --------------------------- |
| `INVALID_NUMBER`     | Número não está no WhatsApp |
| `MESSAGE_NOT_FOUND`  | Mensagem não encontrada     |
| `MEDIA_TOO_LARGE`    | Arquivo excede limite       |
| `INVALID_MEDIA_TYPE` | Tipo de mídia não suportado |
| `MESSAGE_FAILED`     | Falha ao enviar mensagem    |

### Grupos

| Código                  | Descrição                      |
| ----------------------- | ------------------------------ |
| `GROUP_NOT_FOUND`       | Grupo não encontrado           |
| `NOT_GROUP_ADMIN`       | Ação requer ser admin          |
| `PARTICIPANT_NOT_FOUND` | Participante não está no grupo |
| `ALREADY_GROUP_MEMBER`  | Já é membro do grupo           |

### Rate Limiting

| Código                 | Descrição              |
| ---------------------- | ---------------------- |
| `RATE_LIMIT_EXCEEDED`  | Muitas requisições     |
| `DAILY_LIMIT_EXCEEDED` | Limite diário atingido |

***

## Logs e Monitoramento

### Estrutura de Log Recomendada

```javascript theme={null}
function logApiError(error, context) {
  console.error(JSON.stringify({
    timestamp: new Date().toISOString(),
    level: 'error',
    code: error.code,
    message: error.message,
    context: {
      endpoint: context.endpoint,
      instanceId: context.instanceId,
      requestId: context.requestId
    },
    details: error.details
  }));
}
```

### Alertas Recomendados

Configure alertas para:

* Taxa de erros > 5% em 5 minutos
* Erros `INSTANCE_NOT_CONNECTED` (reconectar automaticamente)
* Rate limits frequentes (ajustar throttling)
* Erros 500 (problema no servidor)

***

## Melhores Práticas

<CardGroup cols={2}>
  <Card title="Use Códigos de Erro" icon="code">
    Base sua lógica no `error.code`, não na mensagem (que pode mudar).
  </Card>

  <Card title="Implemente Retry" icon="repeat">
    Use exponential backoff para erros temporários (429, 500, 503).
  </Card>

  <Card title="Valide Antes" icon="check">
    Valide números com `/contacts/check` antes de enviar mensagens.
  </Card>

  <Card title="Monitore Erros" icon="chart-line">
    Registre e monitore erros para identificar padrões.
  </Card>
</CardGroup>

***

## Próximos Passos

<CardGroup cols={2}>
  <Card title="Rate Limits" icon="gauge" href="/support/rate-limits">
    Entenda os limites da API
  </Card>

  <Card title="Troubleshooting" icon="wrench" href="/support/troubleshooting">
    Soluções para problemas comuns
  </Card>
</CardGroup>
