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

# Errores

> Formato de errores, códigos comunes y cómo manejarlos.

## Formato de error

Todos los errores devuelven la misma estructura:

```json theme={null}
{
  "error": {
    "code": "ERROR_CODE",
    "message": "Descripción legible del error.",
    "status": 400,
    "details": {}
  },
  "meta": {
    "requestId": "550e8400-e29b-41d4-a716-446655440000"
  }
}
```

* `code`: Código de error constante. Usalo para lógica programática.
* `message`: Descripción para humanos. Puede cambiar, no lo uses para comparar.
* `status`: Status HTTP.
* `details`: Información adicional (opcional). En errores de validación, incluye los campos con problemas.
* `requestId`: Identificador único de la request. Incluilo si necesitás soporte.

***

## Códigos de error

### Validación (400)

| Código                   | Descripción                                                |
| ------------------------ | ---------------------------------------------------------- |
| `VALIDATION_ERROR`       | Request con datos inválidos. `details` incluye los campos. |
| `MISSING_REQUIRED_FIELD` | Falta un campo obligatorio en el body.                     |
| `INVALID_PHONE`          | Número de teléfono con formato inválido.                   |
| `INVALID_CHANNEL`        | El canal (número) no existe o no está conectado.           |
| `INVALID_MESSAGE_TYPE`   | Tipo de mensaje no soportado.                              |
| `INVALID_CURSOR`         | Cursor de paginación inválido o expirado.                  |
| `INVALID_FILTER`         | Parámetro de filtro no válido.                             |

### Autenticación y permisos (401/403)

| Código                   | Descripción                                             |
| ------------------------ | ------------------------------------------------------- |
| `INVALID_API_KEY`        | API key inválida, expirada o revocada.                  |
| `INSUFFICIENT_SCOPE`     | La API key no tiene el scope necesario.                 |
| `CHANNEL_NOT_CONNECTED`  | El canal no está conectado o verificado.                |
| `SERVICE_WINDOW_EXPIRED` | La ventana de 24hs expiró. Solo podés enviar templates. |

### Recursos (404)

| Código                   | Descripción                               |
| ------------------------ | ----------------------------------------- |
| `CONTACT_NOT_FOUND`      | El contacto no existe.                    |
| `CONVERSATION_NOT_FOUND` | La conversación no existe.                |
| `MESSAGE_NOT_FOUND`      | El mensaje no existe.                     |
| `TEMPLATE_NOT_FOUND`     | El template no existe o no está aprobado. |

### Conflictos (409)

| Código                   | Descripción                                                  |
| ------------------------ | ------------------------------------------------------------ |
| `CONTACT_ALREADY_EXISTS` | Ya existe un contacto con ese número de teléfono.            |
| `IDEMPOTENCY_CONFLICT`   | Otra request con la misma `Idempotency-Key` está en proceso. |

### Límites (429)

| Código         | Descripción                                                |
| -------------- | ---------------------------------------------------------- |
| `RATE_LIMITED` | Superaste el límite de requests. Ver header `Retry-After`. |

### Servidor (500)

| Código           | Descripción                                                                   |
| ---------------- | ----------------------------------------------------------------------------- |
| `INTERNAL_ERROR` | Error interno del servidor. Si persiste, contactá soporte con el `requestId`. |

***

## Cómo manejar errores

```javascript theme={null}
const res = await fetch('https://api.waspytech.com/api/v2/messages', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer wspy_...',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ ... })
});

if (!res.ok) {
  const { error, meta } = await res.json();

  switch (error.code) {
    case 'RATE_LIMITED':
      // Esperar y reintentar
      break;
    case 'SERVICE_WINDOW_EXPIRED':
      // Enviar un template en vez de texto libre
      break;
    case 'CONTACT_ALREADY_EXISTS':
      // El contacto ya existe, usar el existente
      break;
    default:
      console.error(`Error ${error.code}: ${error.message} (${meta.requestId})`);
  }
}
```

***

## Errores retryable

| Código                 | ¿Reintentar?                          |
| ---------------------- | ------------------------------------- |
| `RATE_LIMITED`         | Sí, después de `Retry-After` segundos |
| `IDEMPOTENCY_CONFLICT` | Sí, después de unos segundos          |
| `INTERNAL_ERROR`       | Sí, con backoff exponencial           |
| Todos los demás        | No, la request es incorrecta          |
