# Errores

> Códigos de error de la API de Simplo, clases de error del SDK por status HTTP y las reglas de reintento automático.

Toda falla del SDK lanza una subclase de `SimploError`. Captura estrecho
cuando puedas actuar sobre el caso, amplio en el resto:

```ts
import Simplo, { RateLimitError, SimploError, ValidationError } from '@simplohq/sdk';

const simplo = new Simplo();

try {
  await simplo.dtes.emit(params);
} catch (error) {
  if (error instanceof ValidationError) {
    // Input malo — corrige la request, no la reintentes tal cual.
    for (const issue of error.details ?? []) {
      console.error(`${issue.field}: ${issue.code} — ${issue.message}`);
    }
  } else if (error instanceof RateLimitError) {
    // El SDK ya reintentó; frena al llamador.
    console.error(`Rate limit. Reintenta en ${error.retryAfter ?? '?'}s`);
  } else if (error instanceof SimploError) {
    console.error(error.status, error.code, error.message, error.requestId);
  } else {
    throw error; // error de programación — no lo tragues
  }
}
```

## Propiedades del error

| Propiedad   | Tipo                  | Descripción                                                          |
| ----------- | --------------------- | -------------------------------------------------------------------- |
| `status`    | `number \| undefined` | Status HTTP (ausente en fallas de conexión)                          |
| `code`      | `string \| undefined` | Código de la API legible por máquina, ej. `"VALIDATION_ERROR"`       |
| `message`   | `string`              | Descripción legible por humanos                                      |
| `requestId` | `string \| undefined` | ID de la request — inclúyelo al contactar soporte                    |
| `details`   | `ValidationIssue[]`   | Issues a nivel de campo (`field`, `code`, `message`) en errores de validación |
| `action`    | `string \| undefined` | Siguiente paso recomendado por la API, cuando existe                 |
| `docUrl`    | `string`              | Link a la documentación relevante                                    |

## Clases de error por status

| Status  | Clase                 | ¿Reintentar?           | Causas típicas                                              |
| ------- | --------------------- | ---------------------- | ----------------------------------------------------------- |
| 400/422 | `ValidationError`     | No — corrige la request | Dígito verificador de RUT inválido, campos requeridos ausentes |
| 401     | `AuthenticationError` | No — corrige credenciales | API key errónea o revocada ([Autenticación](/comienza/autenticacion/)) |
| 403     | `PermissionError`     | No                     | La key no tiene el permiso o rol requerido                  |
| 404     | `NotFoundError`       | No                     | ID equivocado, o recurso de otra empresa                    |
| 409     | `ConflictError`       | Depende (ver abajo)    | Folio duplicado; idempotency key aún en vuelo               |
| 429     | `RateLimitError`      | Automático             | Demasiadas requests (los límites son por empresa)           |
| 5xx     | `ServerError`         | Automático (si es seguro) | Problema transitorio de la API                           |
| —       | `ConnectionError`     | Automático (si es seguro) | Falla de red, DNS, timeout                               |
| —       | `WebhookVerificationError` | No — rechaza la entrega | Firma mala, timestamp vencido ([Webhooks](/referencia/webhooks/)) |

## Códigos que vas a ver como integrador

| Código                        | Descripción                                                                                                          |
| ----------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| `401`                         | Credencial inválida, revocada o expirada. La respuesta no distingue el motivo (anti-enumeración): revisa el header y el prefijo `sk_simplo_`. |
| `409 IDEMPOTENCY_IN_PROGRESS` | La misma `Idempotency-Key` aún se está procesando. Espera y consulta el estado en vez de reintentar de inmediato.     |
| `409` (folio duplicado)       | Conflicto de folio al emitir.                                                                                        |
| `422 IDEMPOTENCY_BODY_MISMATCH` | Reutilizaste una `Idempotency-Key` con un body distinto al original. Usa una key nueva por cada emisión distinta.  |
| `429`                         | Rate limit: 120 llamadas por minuto por empresa, compartido entre REST y MCP. Espera y reintenta.                     |
| `503` (idempotencia)          | Servicio de idempotencia temporalmente no disponible al emitir. Reintenta con la **misma** key.                       |

## Reintentos automáticos

El SDK reintenta en `429`, `5xx` y errores de red con backoff exponencial y
jitter, respetando el header `Retry-After`. Por defecto: 2 reintentos;
sobrescríbelo con `maxRetries` en el cliente o por request.

**Regla de seguridad:** un `POST` solo se reintenta cuando lleva una
`Idempotency-Key`. `dtes.emit` genera una automáticamente (UUID v4), así que
los reintentos de emisión nunca pueden duplicar un documento. Otros POSTs
(`folios.upload`, `webhooks.create`) no se reintentan automáticamente —
vuelve a llamarlos tú si hace falta; ambos son seguros de re-ejecutar (un CAF
duplicado devuelve `ConflictError`).

```ts
const simplo = new Simplo({ maxRetries: 3, timeout: 30_000 });
await simplo.dtes.list({}, { maxRetries: 0 }); // override por request
```

## Relacionado

- [Emisión](/referencia/emision/) — idempotencia en detalle
- [Límites](/referencia/limites/) — el rate limit por empresa

---

Versión HTML: https://docs.simplo.cl/referencia/errores/ · Índice para agentes: https://docs.simplo.cl/llms.txt
