# Errores

> Catálogo de errores de la API de Trevol: códigos estables, estado HTTP, cuándo pasan y si se reintentan. Formato application/problem+json (RFC 9457).

Fuente: https://platform.trevol.si/docs/errores

Cada error trae un `code` estable (programa contra él, no contra el texto), el estado HTTP, un `detail` en español, `retryable` y el `request_id` de la petición. El `type` apunta a esta página, con un ancla por código: `https://platform.trevol.si/docs/errores#validation_error`.

```json respuesta
{
	"type": "https://platform.trevol.si/docs/errores#validation_error",
	"title": "Los datos no son válidos",
	"status": 422,
	"code": "validation_error",
	"detail": "La tarifa de IVA debe ser una de la tabla 13.3.11: 0.00, 5.00, 16.00, 19.00.",
	"errors": [
		{ "field": "items[0].taxes[0].rate", "pointer": "/items/0/taxes/0/rate", "message": "…" }
	],
	"retryable": false,
	"request_id": "req_…"
}
```

Cuando la DIAN rechaza un documento, `document.dian.rules` trae cada regla con su explicación y cómo corregirla: [Reglas de la DIAN](/docs/errores/reglas-dian). Qué se reintenta y cómo: [Reintentos](/docs/reintentos).

## Autenticación y permisos

### authentication_required

**Falta la llave de la API** · HTTP 401 · No se reintenta: corrige primero

Falta `Authorization: Bearer` con la llave.

### invalid_api_key

**La llave de la API no es válida** · HTTP 401 · No se reintenta: corrige primero

La llave no existe, fue revocada o no es de la API (debe empezar por `tvl_test_` o `tvl_live_`).

### permission_denied

**Sin permiso para esto** · HTTP 403 · No se reintenta: corrige primero

La llave es de solo lectura, o la petición viene de una IP que la llave no permite.

## El pedido

### not_found

**No existe** · HTTP 404 · No se reintenta: corrige primero

La ruta no existe, o el documento no es de la empresa y el ambiente de la llave.

### method_not_allowed

**Método no permitido** · HTTP 405 · No se reintenta: corrige primero

La ruta existe pero no con ese método (la cabecera `Allow` dice cuáles).

### unsupported_version

**Versión de la API desconocida** · HTTP 400 · No se reintenta: corrige primero

`Trevol-Version` trae una versión que no existe.

### invalid_json

**El cuerpo no es JSON válido** · HTTP 400 · No se reintenta: corrige primero

El cuerpo no es JSON o no es un objeto.

### invalid_request

**El pedido no es válido** · HTTP 400 · No se reintenta: corrige primero

El pedido no es válido (por ejemplo, una `Idempotency-Key` con caracteres no permitidos).

### validation_error

**Los datos no son válidos** · HTTP 422 · No se reintenta: corrige primero

Los datos no son válidos. `errors[]` trae cada campo con su puntero (RFC 6901). No se gastó ningún número.

## Idempotencia y duplicados

### idempotency_key_required

**Falta Idempotency-Key** · HTTP 400 · No se reintenta: corrige primero

Crear o corregir un documento sin `Idempotency-Key`.

### idempotency_key_reused

**Esa Idempotency-Key ya se usó con otro pedido** · HTTP 422 · No se reintenta: corrige primero

La misma `Idempotency-Key` con otro cuerpo u otra operación. Usa una clave nueva por pedido.

### request_in_progress

**Ese pedido todavía se está procesando** · HTTP 409 · Se puede reintentar

Otra petición está enviando ese documento ahora. Consulta su estado en unos segundos.

### external_id_in_use

**Ese external_id ya existe** · HTTP 409 · No se reintenta: corrige primero

Ya hay un documento con ese `external_id` en la empresa y el ambiente; `existing_id` dice cuál (con el prefijo de su recurso). El `external_id` es único entre facturas, notas, documentos soporte y equivalentes (y sus notas); aparte, entre nóminas y sus ajustes; y aparte, entre eventos RADIAN.

### duplicate_document

**Ya existe un documento igual** · HTTP 409 · No se reintenta: corrige primero

Ya hay un documento vivo igual: una nómina (102) del mismo trabajador y mes en producción, o un evento RADIAN del mismo código sobre la misma factura. `existing_id` dice cuál (`pr_…`, `rev_…`). Para reintentar un evento: `POST /v1/radian_events/{id}/send`; para cambiar una nómina: una nota de ajuste.

## Documentos y la DIAN

### invalid_state

**El documento no está en un estado que lo permita** · HTTP 409 · No se reintenta: corrige primero

El documento no está en un estado que lo permita (por ejemplo, corregir uno ya validado: para eso es la nota; un `PUT` sobre un documento que Trevol o la DIAN están verificando —también el set de pruebas de la nómina y del documento equivalente—: espera el resultado; o reenviar un evento RADIAN rechazado: un rechazo es final).

### previous_event_pending

**Falta el evento anterior en la DIAN** · HTTP 409 · Se puede reintentar

Solo en la versión 2026-10-21: el evento (031, 032, 033) necesita que la DIAN muestre el anterior (`previous`) y todavía no aparece. No se envió nada; el evento queda en error con su número (viene en `document`): reintenta con `POST /v1/radian_events/{id}/send`. En 2026-10-22 es un 202 `processing` y Trevol lo manda cuando aparezca.

### tacit_acceptance_not_due

**La aceptación tácita todavía no procede** · HTTP 422 · No se reintenta: corrige primero

La aceptación tácita (034) todavía no procede. `available_from` dice desde cuándo (3 días hábiles después del recibo del bien) y `rules` las reglas LGC que lo impiden (las locales llevan `local: true`). El evento queda en error con su número: reintenta con `POST …/send` cuando proceda. `GET /v1/invoices/{id}/tacit_acceptance` (o, por CUFE, `GET /v1/radian_events/tacit_acceptance?cufe=…`) lo dice antes.

### dian_rejected

**La DIAN rechazó el documento** · HTTP 422 · No se reintenta: corrige primero

La DIAN rechazó el documento. `document` trae el documento con `dian.rules` traducidas (ver las [reglas de la DIAN](/docs/errores/reglas-dian)); se corrige con `PUT` y el mismo número.

### file_unavailable

**El archivo no está disponible** · HTTP 409 · No se reintenta: corrige primero

El documento todavía no tiene archivos (no está validado), o no se pudieron preparar ahora (503, reintentable).

### dian_unavailable

**La DIAN no respondió** · HTTP 503 · Se puede reintentar

Solo en la versión 2026-10-21: la DIAN no contestó. El documento queda en error y Trevol lo verifica en segundo plano (solo consulta; no reenvía). Reintenta con la misma `Idempotency-Key`: sigue con el mismo documento. En 2026-10-22 la respuesta es un 202 `processing`.

## Empresa y numeración

### company_not_enabled

**La empresa no está habilitada para facturar** · HTTP 422 · No se reintenta: corrige primero

La empresa no ha terminado la habilitación ante la DIAN, o le falta algo para esa familia de documentos. `reason` dice qué: `missing_software` (el software del modo), `missing_pin`, `payroll_not_enabled` (la nómina no está habilitada ni en pruebas) o `missing_legal_representative` (eventos 030 y 032). Se revisa antes de numerar.

### numbering_unavailable

**La numeración no está disponible** · HTTP 422 · No se reintenta: corrige primero

No hay numeración disponible: sin resolución activa (o sin rango de documento soporte o POS), agotada o vencida, o ContaPyme lleva la numeración de producción. `reason`: `no_resolution`, `resolution_exhausted`, `resolution_expired`, `resolution_not_yet_valid`, `prefix_in_use` o `missing_technical_key` (POS).

### certificate_problem

**Hay un problema con el certificado de la empresa** · HTTP 422 · No se reintenta: corrige primero

El certificado de la empresa falta o no sirve para firmar.

## Saldo y recargas

### insufficient_balance

**No hay saldo** · HTTP 402 · No se reintenta: corrige primero

Producción sin saldo. El documento queda `pending` con su número y se envía al reintentar con saldo.

### top_up_below_minimum

**La recarga es menor que la mínima** · HTTP 422 · No se reintenta: corrige primero

Preparar una recarga (`POST /v1/balance/top_ups`) por menos de la recarga mínima ($ 5.000). `minimum_cop` dice cuánto es.

### top_up_above_maximum

**La recarga es mayor que la máxima** · HTTP 422 · No se reintenta: corrige primero

Preparar una recarga (`POST /v1/balance/top_ups`) por más de la recarga máxima. `maximum_cop` dice cuánto es.

### top_ups_unavailable

**Las recargas no están disponibles** · HTTP 503 · Se puede reintentar

Las recargas no están disponibles en este momento. `Retry-After` dice cuándo volver a intentar.

## Límites y disponibilidad

### webhook_limit_reached

**Ya hay el máximo de endpoints de webhooks** · HTTP 409 · No se reintenta: corrige primero

Ya hay 5 webhooks en la empresa y el ambiente. Borra uno para crear otro.

### rate_limited

**Demasiadas peticiones** · HTTP 429 · Se puede reintentar

Pasaste un límite de la llave. `Retry-After` dice cuántos segundos esperar.

### internal_error

**Error interno de Trevol** · HTTP 500 · Se puede reintentar

Error de Trevol. Escríbenos con el `request_id`.
