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

# Errores

> Taxonomía de errores de la API v2 — estructura estable, tipos y catálogo de códigos

# Errores

La API v2 devuelve **un solo formato de error** en toda respuesta ≥ 400. Está
diseñado para que puedas manejar errores con código estable y sin parsear texto.

## Estructura del error

```json theme={null}
{
  "error": {
    "type": "invalid_request_error",
    "code": "parameter_missing",
    "message": "Falta el parámetro requerido 'master_entity_id'.",
    "param": "master_entity_id",
    "resource": "ment_4829301923847",
    "doc_url": "https://docs.tupana.ai/v2/errors#parameter_missing",
    "request_id": "req_8f3a9c2b1e7d4"
  }
}
```

| Campo | Siempre | Descripción |
| - | :-: | - |
| `type` | ✓ | Categoría amplia y **estable**. Mapea 1:1 al status HTTP (tabla abajo). |
| `code` | ✓ | Código específico, **estable, machine-readable**. Haz tu `switch` sobre esto. |
| `message` | ✓ | Texto para humanos (es-CL). **Puede cambiar — nunca lo parsees.** |
| `param` | — | Campo que causó el error (para formularios). |
| `resource` | — | **Public ID** del recurso involucrado (`docu_…`, `ment_…`, `cred_…`). |
| `doc_url` | ✓ | Link directo a la explicación de este `code`. |
| `request_id` | ✓ | ID de correlación (`req_…`). Inclúyelo al contactar soporte. |

<Warning>
  Maneja los errores por **`code`** (estable), no por `message` (puede cambiar) ni
  por el status HTTP solo (varios `code` comparten status).
</Warning>

## Tipos de error y status HTTP

| `type` | HTTP | Cuándo ocurre | ¿Reintentar? |
| - | :-: | - | :-: |
| `invalid_request_error` | 400 | Request mal formado o parámetro inválido | No — corrige el request |
| `authentication_error` | 401 | Falta la API Key o es inválida | No |
| `permission_error` | 403 | La API Key no tiene acceso a ese recurso | No |
| `not_found_error` | 404 | El recurso (public ID) no existe | No |
| `validation_error` | 422 | El documento no cumple una regla de negocio o del SII | No — corrige los datos |
| `conflict_error` | 409 | Estado conflictivo (folio/RUT duplicado) | No |
| `idempotency_error` | 409 | Reusaste una `Idempotency-Key` con un body distinto | No |
| `credential_error` | 400 | Credencial SII/certificado inválida, incompleta o bloqueada | Solo tras corregir la credencial |
| `sii_error` | 400 / 503 | El SII rechazó el documento o no está disponible | Sí si es `sii_unavailable` |
| `payment_error` | 400 | Problema al generar el cobro (pasarela / datos bancarios) | No |
| `rate_limit_error` | 429 | Superaste el límite de solicitudes | Sí — con backoff (ver `Retry-After`) |
| `api_error` | 500 / 502 / 503 | Error interno o de un servicio upstream | Sí — con backoff |

### Ejemplo de manejo (pseudo)

```python theme={null}
resp = tupana.documents.create(batch)
if resp.status_code >= 400:
    err = resp.json()["error"]
    if err["code"] == "folios_exhausted":
        alertar_contador("Solicita más CAF en el SII")
    elif err["type"] == "rate_limit_error":
        reintentar_con_backoff(resp.headers["Retry-After"])
    elif err["type"] == "sii_error" and err["code"] == "sii_unavailable":
        reintentar_mas_tarde()
    else:
        log(err["request_id"], err["message"])
```

***

## Catálogo de códigos

<Note>
  Los códigos de **Comunes**, **Cesiones** y **Recaudación** ya se emiten en
  producción. Las secciones marcadas con **⏳** están en implementación: hoy esos
  endpoints devuelven `parameter_missing`/`parameter_invalid` en errores de campo
  (con `param`) y `validation_error` con mensaje en reglas de negocio; los códigos
  específicos listados se están desplegando.
</Note>

### Comunes (todas las APIs)

| `code` | `type` | HTTP | Significado |
| - | - | :-: | - |
| `parameter_missing` | invalid\_request\_error | 400 | Falta un parámetro requerido (ver `param`). |
| `parameter_invalid` | invalid\_request\_error | 400 | Un parámetro tiene formato o valor inválido (ver `param`). |
| `unauthenticated` | authentication\_error | 401 | Falta la API Key o es inválida/revocada. |
| `forbidden` | permission\_error | 403 | La API Key no tiene acceso a ese recurso. |
| `resource_missing` | not\_found\_error | 404 | El public ID no existe (ver `resource`). |
| `conflict` | conflict\_error | 409 | Conflicto con datos existentes. |
| `rate_limited` | rate\_limit\_error | 429 | Demasiadas solicitudes. Respeta `Retry-After`. |
| `internal_error` | api\_error | 500 | Error interno. Reintenta; si persiste, reporta el `request_id`. |

### ⏳ Facturación — Emisión de documentos

| `code` | `type` | HTTP | Significado |
| - | - | :-: | - |
| `no_documents` | invalid\_request\_error | 400 | La lista `documents` está vacía. |
| `too_many_documents` | invalid\_request\_error | 413 | Máximo 200 documentos por batch. |
| `issuer_rut_missing` | invalid\_request\_error | 400 | Falta el RUT del emisor en el documento. |
| `issuer_not_found` | not\_found\_error | 404 | No existe una empresa con ese RUT emisor. |
| `issuer_forbidden` | permission\_error | 403 | La API Key no puede emitir por esa empresa. |
| `no_active_credentials` | credential\_error | 400 | La empresa emisora no tiene credenciales de emisión activas. |
| `certificate_password_required` | credential\_error | 400 | Ese tipo de DTE requiere clave del certificado digital. |
| `receiver_required` | validation\_error | 422 | Este tipo de documento exige receptor. |
| `receiver_data_incomplete` | validation\_error | 422 | Faltan datos del receptor (dirección, giro, comuna). Ver `param`. |
| `dte_field_required` | validation\_error | 422 | Falta un campo obligatorio para ese tipo de DTE. Ver `param`. |
| `detail_line_limit` | validation\_error | 422 | El facturador gratuito del SII permite máximo 10 líneas por documento. |
| `negative_amount` | validation\_error | 422 | Montos negativos solo se permiten en boletas (39/41). |
| `folio_duplicate` | conflict\_error | 409 | Ya existe ese folio para el tipo de DTE en el período. |

### ⏳ Facturación — Guía de despacho (DTE 52) y líneas exentas

El batch responde **422** con el **mismo cuerpo que v1**, no con el sobre de
errores v2: los errores van bajo `documents`, con la posición del documento como
llave (`"0"`, `"1"`...) y la ruta del campo adentro. No tienen un `code` propio:
identifica el campo por su ruta.

```json theme={null}
{
  "documents": {
    "0": {
      "transport_data": {
        "gross_weight": ["Requerido en guías de traslado de exportación (transport_type 8 o 9): el SII lo exige en Transporte/Aduana."]
      }
    }
  }
}
```

| Caso | HTTP |
| - | :-: |
| `transport_data.transport_type` fuera de `"1"`–`"9"` o `dispatch_type` fuera de `"1"`–`"3"` | 422 |
| `dispatch_type` con `transport_type` `"5"` (traslado interno) | 422 |
| Sólo uno de `driver_rut` / `driver_name` | 422 |
| `destination_address` > 70, `destination_district` > 20 o `destination_city` > 20 caracteres | 422 |
| `transfer_issuer_code` o datos de Aduana (`departure_port_code`, `arrival_port_code`, `gross_weight`, `gross_weight_unit_code`, `total_packages`, `package_type_code`) con `transport_type` distinto de `"8"`/`"9"` | 422 |
| Traslado `"8"`/`"9"` sin `transfer_issuer_code`, puertos, peso bruto o unidad, con emisor del facturador de mercado | 422 |
| `transfer_issuer_code` `"4"` sin `authorization_resolution_number` / `authorization_resolution_date`, o esos campos con otro código | 422 |
| Puerto, unidad o tipo de bulto fuera de las tablas de Aduana; `gross_weight` o `total_packages` ≤ 0; `total_packages` sin `package_type_code` | 422 |
| `details[].is_exempt` en un documento que no es DTE 52 | 422 |
| Datos de Aduana, destino de la madera (`destination_commune_role`, `destination_block_role`, `destination_property_role`, `work_execution_notice`, `destination_latitude`, `destination_longitude`) o `details[].is_exempt` con emisor del **facturador gratuito del SII**: *"no disponible para emisores del facturador gratuito del SII"* | 422 |
| `trailer_plate` > 8 caracteres; `arrival_date` anterior a `departure_date`; `transfer_reason` > 200 o `transport_unknown_reason` > 100 caracteres; rol predial de destino de la madera con otra cosa que 1 a 6 dígitos | 422 |
| **Desde el 1 de noviembre de 2026 (Res. Ex. SII N°154):** guía sin `transport_type`; sin patente, transportista o chofer y sin `transport_unknown_reason`; sin dirección o comuna de destino (propia o del receptor); sin `departure_date` o `departure_time`; línea sin `unit`; venta (`"1"`/`"9"`) sin `unit_price`; traslado sin venta sin precio ni `transfer_reason`; `timber_enabled` sin rol predial de destino. Hasta esa fecha son avisos `res154_*` (ver abajo) | 422 |

Detalle de cada campo en [Emisión masiva de documentos (v1)](/api-reference/documents/batch), bloque "Guía de Despacho (DTE 52)".

### ⏳ Facturación — Campos desconocidos

Un campo que no existe en el documento (por ejemplo `header.transfer_indicator`)
**no se usa al emitir**. Según la API key:

* **Modo aviso** (integraciones existentes): el documento se crea sin ese campo
  y la respuesta del batch trae un arreglo `warnings`. No es un error: el status
  es el de un batch aceptado.
* **Modo estricto** (API keys nuevas): la API responde **422** con el campo bajo
  `documents` → posición → ruta (mismo formato que v1) y no crea el batch.

```json theme={null}
{
  "warnings": [
    {
      "document_index": 0,
      "field": "header.transfer_indicator",
      "code": "unknown_field",
      "message": "Campo desconocido: se ignoró.",
      "suggestion": "transport_data.transport_type"
    }
  ]
}
```

| Campo | Descripción |
| - | - |
| `document_index` | Posición del documento en `documents` (desde 0). |
| `field` | Ruta del campo dentro del documento. |
| `code` | Tipo de aviso: `unknown_field` (campo desconocido), `invalid_rut` (RUT de transportista o chofer con dígito verificador inválido: el documento se emite igual y el aviso nunca pasa a 422, ni con validación estricta) o un código `res154_*` / `res75_timber_destination` (dato de la guía que la Res. Ex. SII N°154 vuelve obligatorio el 1 de noviembre de 2026; ver tabla siguiente). |
| `message` | Texto para humanos. **Puede cambiar — nunca lo parsees.** |
| `suggestion` | Campo correcto si se reconoce el error, o `null`. |

| Campo enviado | `suggestion` |
| - | - |
| `header.transfer_indicator` | `transport_data.transport_type` |
| `export_data.export_clause` | `export_data.sale_clause_code` |
| `export_data.destination_country` | `export_data.destination_country_code` |

<Warning>
  Un aviso significa que el dato **no llegó al documento**: con
  `header.transfer_indicator` la guía sale como venta (`transport_type` `"1"`) y con
  `export_data.export_clause` la factura de exportación sale sin cláusula de venta.
</Warning>

### ⏳ Facturación — Avisos de la Resolución 154 (guías de despacho)

Hasta el **31 de octubre de 2026** la guía se emite aunque falten los datos que la
Res. Ex. SII N°154 vuelve obligatorios; la respuesta del batch (v1 y v2, con o sin
API key) los lista en `warnings` con estos códigos. Desde el **1 de noviembre de
2026** los mismos casos responden **422**, salvo `res154_trailer_plate`, que sigue
siendo sólo un aviso.

| `code` | `field` | Qué falta |
| - | - | - |
| `res154_transfer_type` | `transport_data.transport_type` | Tipo de traslado |
| `res154_carrier` | `transport_data.transport_plate`, `transport_rut` o `driver_rut` | Patente, RUT del transportista o chofer, sin `transport_unknown_reason` |
| `res154_destination` | `transport_data.destination_address` o `destination_district` | Dirección o comuna de destino (propia o del receptor) |
| `res154_departure` | `transport_data.departure_date` o `departure_time` | Fecha u hora de inicio del traslado |
| `res154_unit` | `details[n].unit` | Unidad de medida de la línea |
| `res154_transfer_reason` | `details[n].unit_price` o `transport_data.transfer_reason` | Precio en una venta, o motivo del traslado cuando se omite el precio |
| `res154_trailer_plate` | `transport_data.trailer_plate` | Patente del carro, si el vehículo lleva uno (nunca 422) |
| `res75_timber_destination` | `transport_data.destination_*_role` | Rol predial de destino de la madera (`timber_enabled`, facturador de mercado) |

```json theme={null}
{
  "warnings": [
    {
      "document_index": 0,
      "field": "transport_data.departure_time",
      "code": "res154_departure",
      "message": "La hora de inicio del traslado es obligatoria.",
      "suggestion": "Informe transport_data.departure_time (HH:MM)."
    }
  ]
}
```

Detalle de cada campo y de la anulación de guías en [Emisión masiva de documentos (v2)](/api-reference/v2/documents/batch), sección "Resolución 154".

### ⏳ Facturación — Boleta de Honorarios (DTE 80/90)

| `code` | `type` | HTTP | Significado |
| - | - | :-: | - |
| `authorized_user_rut_not_allowed` | validation\_error | 422 | `authorized_user_rut` solo aplica a boletas de honorarios (80/90). |
| `authorized_user_credential_missing` | credential\_error | 400 | No hay credencial `sii_company` activa del usuario autorizado. |
| `retention_type_invalid` | invalid\_request\_error | 400 | `retention_type` debe ser `RETRECEPTOR`, `RETEMISOR` o `RETTERCERO`. |

### ⏳ Credenciales

| `code` | `type` | HTTP | Significado |
| - | - | :-: | - |
| `credential_password_required` | invalid\_request\_error | 400 | Falta `user_rut` y/o `password`. |
| `certificate_invalid` | credential\_error | 400 | El certificado (.pfx) es inválido o la clave es incorrecta. |
| `sii_credentials_invalid` | credential\_error | 400 | El SII rechazó el RUT/clave ("Usuario no autorizado"). |
| `credential_locked` | conflict\_error | 409 | La credencial está en uso por otra operación. Reintenta en unos segundos. |

### ⏳ SII (emisión y consultas)

| `code` | `type` | HTTP | Significado |
| - | - | :-: | - |
| `folios_exhausted` | sii\_error | 400 | No quedan folios (CAF). Solicita más en el SII. |
| `sii_rejected` | sii\_error | 400 | El SII rechazó el documento. Revisa los datos. |
| `sii_unauthorized` | sii\_error | 400 | El usuario no está autorizado en el SII para esta operación. |
| `sii_session_expired` | sii\_error | 400 | La sesión del SII expiró. Revalida la credencial. |
| `sii_unavailable` | sii\_error | 503 | El SII no está disponible. Reintenta en unos minutos. |

### Recaudación (cobros / payment requests)

| `code` | `type` | HTTP | Significado |
| - | - | :-: | - |
| `document_ids_empty` | invalid\_request\_error | 400 | `document_ids` debe tener al menos un documento. |
| `mixed_payers` | invalid\_request\_error | 400 | Todos los documentos deben ser del mismo receptor/pagador. |
| `cannot_mix_modes` | invalid\_request\_error | 400 | `document_ids` no se combina con campos de emisión (`items`, `amount`, etc.). |
| `document_not_owned` | invalid\_request\_error | 400 | Un documento no pertenece al receptor indicado. |
| `document_not_payable` | invalid\_request\_error | 400 | El tipo de documento no es cobrable. |
| `document_already_paid` | invalid\_request\_error | 400 | El documento ya está pagado. |
| `sandbox_document_required` | invalid\_request\_error | 400 | Con API Key sandbox, los documentos deben ser sandbox. |
| `banking_info_missing` | payment\_error | 400 | El receptor no tiene información bancaria configurada. |
| `resource_missing` | not\_found\_error | 404 | El documento o el receptor no existe. |

### Cesiones

| `code` | `type` | HTTP | Significado |
| - | - | :-: | - |
| `document_ids_empty` | invalid\_request\_error | 400 | `document_ids` debe tener al menos un documento. |
| `assignee_data_incomplete` | invalid\_request\_error | 400 | Faltan datos del cesionario (`assignee_rut`, `assignee_dv`, `assignee_email`, razón social o dirección). |
| `assignor_email_missing` | invalid\_request\_error | 400 | Falta `assignor_email` (o email de la empresa cedente). |
| `document_not_cessionable` | invalid\_request\_error | 400 | Solo facturas electrónicas DTE 33/34 pueden cederse. |
| `no_active_credentials` | credential\_error | 400 | La entidad no tiene credencial SII válida para ceder. |
| `resource_missing` | not\_found\_error | 404 | Alguno de los documentos no existe o no pertenece a esta entidad. |

### ⏳ Documentos Programados

| `code` | `type` | HTTP | Significado |
| - | - | :-: | - |
| `next_issue_date_in_past` | invalid\_request\_error | 400 | La próxima fecha de emisión debe ser futura. |
| `frequency_invalid` | invalid\_request\_error | 400 | Frecuencia inválida (`monthly`, `quarterly`, `yearly`). |

### ⏳ Webhooks

| `code` | `type` | HTTP | Significado |
| - | - | :-: | - |
| `webhook_url_invalid` | invalid\_request\_error | 400 | La `webhook_url` es inválida o no es HTTPS. |
| `event_type_invalid` | invalid\_request\_error | 400 | El `event_type` no está soportado. |

***

## Ejemplos por escenario

### Falta un campo del receptor (validación)

```json theme={null}
{
  "error": {
    "type": "validation_error",
    "code": "receiver_data_incomplete",
    "message": "El receptor requiere dirección para una factura afecta (DTE 33).",
    "param": "document_receiver.address",
    "resource": "ment_4829301923847",
    "doc_url": "https://docs.tupana.ai/v2/errors#receiver_data_incomplete",
    "request_id": "req_2b7e1c9a4f0"
  }
}
```

### El SII se quedó sin folios

```json theme={null}
{
  "error": {
    "type": "sii_error",
    "code": "folios_exhausted",
    "message": "No quedan folios disponibles para factura electrónica (33). Solicita más folios (CAF) en el SII.",
    "resource": "ment_4829301923847",
    "doc_url": "https://docs.tupana.ai/v2/errors#folios_exhausted",
    "request_id": "req_5a1d8f3b2c6"
  }
}
```

### Recurso no encontrado (public ID inexistente)

```json theme={null}
{
  "error": {
    "type": "not_found_error",
    "code": "resource_missing",
    "message": "No existe un documento con id 'docu_0000000000000'.",
    "resource": "docu_0000000000000",
    "doc_url": "https://docs.tupana.ai/v2/errors#resource_missing",
    "request_id": "req_9c4e2a7f1b8"
  }
}
```

### Límite de solicitudes

```json theme={null}
{
  "error": {
    "type": "rate_limit_error",
    "code": "rate_limited",
    "message": "Demasiadas solicitudes. Reintenta después de 5 segundos.",
    "doc_url": "https://docs.tupana.ai/v2/errors#rate_limited",
    "request_id": "req_1f6b3d9e0a2"
  }
}
```

Respuesta incluye el header `Retry-After: 5`.

***

## Idempotencia y errores

Los endpoints de escritura (emisión, cobros) aceptan el header `Idempotency-Key`.
Si reintentas **con la misma key y el mismo body**, la API devuelve la respuesta
original **sin repetir la operación** (no se re-emite al SII). Si reutilizas la
misma key con un **body distinto**, obtienes `idempotency_key_reused` (409).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.