Catálogo de errores
Referencia de los códigos que emite la API, con next_action accionable por código y request_id para correlacionar con soporte.
Todos los errores Notta siguen el shape { code, message, request_id, hint?, next_action?, detail?, docs_url? }. El campo next_action es enumerable y está diseñado para que un agente LLM pueda razonar qué hacer sin necesidad de leer el message.
Estructura
Incluye el request_id al contactar soporte: es el identificador que correlaciona tu request con los logs del servidor.
Toda respuesta de la API lleva además ese mismo identificador en el header X-Request-Id, no solo las de error: también los 200, y también las que no son JSON (/dtes/{id}/xml, /pdf, /muestras). Si necesitas reportar una respuesta exitosa que te parece incorrecta —una lectura que devolvió de menos, un listado que no cuadra— ese header es lo que nos deja encontrar tu request exacto y con qué parámetros salió. Guárdalo también en el camino feliz.
docs_url apunta a la fila exacta de tu código en el catálogo de abajo (p. ej. https://notta.cl/docs/errors#e-caf.not_found). Viene en todo error cuyo código esté documentado aquí; si un error no lo trae, es que su código todavía no tiene fila — nunca un link roto.
Códigos por dominio
Cuando un código no trae next_action (marcado con —), la corrección sale del code más el detail.
Autenticación y permisos
| Código | HTTP | Descripción | next_action |
|---|---|---|---|
unauthorized | 401 | Falta el header Authorization: Bearer | send_bearer_token |
invalid_api_key | 401 | La API key no matchea ninguna key activa | regenerate_api_key |
api_key_expired | 401 | API key expirada | regenerate_api_key |
api_key_revoked | 401 | API key revocada | regenerate_api_key |
forbidden | 403 | Dos causas distintas, y el message dice cuál: scope — la API key no tiene el permiso requerido (dte:write, caf:write, certificates:write, …); o rol — el usuario que actúa no puede hacerlo aunque la key tenga el scope (subir un certificado o pedir folios exige owner/admin). El de rol también llega por sesión del dashboard, donde cambiar de key no ayuda | use_api_key_with_required_scope (solo en el de scope) |
cert_id_missing | 400 | La org no tiene ningún certificado cargado y el verbo firma | upload_certificate |
cert_id_ambiguous | 400 | La org tiene varios certificados vigentes — especifica cuál firma con X-Cert-Id | send_cert_id_header |
org.required | 412 | La sesión de dashboard no tiene organización — completa el onboarding de org (aplica a /certificates, /caf y /api-keys) | — |
org.rut_missing | 412 | La organización de la sesión no tiene RUT registrado — complétalo en el onboarding antes de sincronizar el RCV | — |
onboarding_production_not_authorized | 403 | La org todavía no está habilitada para emitir en producción (palena) | — |
csrf_origin_mismatch | 403 | Origin no permitido para esta acción (protección CSRF de la sesión de dashboard; no aplica al camino Authorization: Bearer) | — |
csrf_blocked | 403 | Variante del anterior que responde el propio endpoint (no el middleware): mutación cross-origin con sesión de dashboard. No aplica al camino Authorization: Bearer, que no tiene sesión que proteger | — |
Validación del payload
| Código | HTTP | Descripción | next_action |
|---|---|---|---|
validation_failed | 400 | El body no pasa el schema — revisa issues[] campo por campo. Incluye el RUT con dígito verificador inválido, salvo en POST /organizations/solicitar-acceso, que tiene código propio (invalid_rut) | fix_body_and_retry |
invalid_json | 400 | El body no es JSON válido | fix_json_body_and_retry |
idempotency_key_missing | 400 | Falta el header Idempotency-Key (obligatorio en todo POST de emisión) | send_idempotency_key_header |
idempotency_key_reused | 409 | Esa Idempotency-Key ya está tomada por otro pedido tuyo que sigue esperando aprobación (otro documento, u otra acción). No se emitió ni se registró nada; pending_id dice cuál la ocupa. Reintentar el MISMO pedido con la misma clave sí devuelve el pendiente original | use_new_idempotency_key |
emisor_rut_mismatch | 422 | El rut_emisor del body no coincide con el RUT del certificado | — |
emisor.profile_incompleto | 422 | Faltan datos del perfil del emisor para emitir (detail.missing) | complete_emisor_profile |
items_empty | 400 | items vacío | — |
items_exceed_max | 400 | items supera el máximo (límite SII; detail.count) | — |
amount_arithmetic | 400 | Los montos declarados no cuadran aritméticamente | — |
references_required | 400 | El tipo_dte exige references y no vienen | — |
reference_invalid_cod_ref | 400 | cod_ref fuera del enum 1/2/3 | — |
text_correction_must_be_zero | 400 | NC de corrección de texto (cod_ref 2) debe llevar montos en cero | — |
dte.tipo_not_supported | 400 | tipo_dte no soportado por este pipeline | fix_tipo_dte_and_retry |
dte.34.invalid_exenta | 422 | DTE 34 (Factura Exenta) con items afectos | fix_tipo_dte_and_retry |
dte.41.afecto_not_allowed | 422 | Boleta Exenta 41 con items afectos | fix_tipo_dte_and_retry |
dte.46.invalid_afecta | 422 | DTE 46 (Factura de Compra) con items exentos — es una operación 100% afecta (cambio de sujeto) | remove_exento_items_and_retry |
dte.mixed_retencion_references | 422 | Una NC/ND mezcla una referencia con retención total de IVA (Factura de Compra 46) y otra sin retención — no hay un total coherente para todo el documento | split_into_separate_documents_by_retencion |
dte.type.prod_not_certified | 422 | Tu organización no tiene ese tipo de documento habilitado para emitir en producción (gate por tipo). El SII autoriza los tipos de documento por empresa: escríbenos para revisarlo | contact_support_to_enable_type |
dte.sii_env_credential_mismatch | 422 | El sii_env del cuerpo dice un ambiente y tu credencial emite en el otro (detail.solicitado y detail.credencial). El ambiente sale de la API key, no del cuerpo: mandar el campo es opcional y sirve de confirmación. No se emitió nada. Para emitir en el ambiente que pediste, usa una API key de ese ambiente. Distinto de sii_env_mismatch, que es un CAF de otro ambiente | use_api_key_matching_sii_env |
dte.field_too_long | 422 | Un campo supera el maxLength que exige el XSD del SII (detail trae field, element, maxLength, actualLength) — atrapado antes de firmar, sin quemar folio | shorten_field_and_retry |
idempotency_conflict | 409 | Mismo Idempotency-Key con otro body — detail.existingDteId apunta al DTE original | — |
Lectura y estado del DTE
| Código | HTTP | Descripción | next_action |
|---|---|---|---|
not_found | 404 | El recurso no existe o pertenece a otra org (DTEs y boletas). El mismo código responde cuando el endpoint no existe (método o ruta no soportados bajo /organizations/* e /invitations/*): si no reconoces la ruta que llamaste, revisa el método y el path antes que el id | — |
dte.xml.not_yet_available | 404 | El DTE todavía no tiene XML — el workflow de firma sigue corriendo | poll_self |
dte.pdf.not_signed | 409 | El DTE existe pero no está firmado — el PDF requiere el TED (síguelo en xml_url) | poll_self |
dte.list.cursor_invalido | 422 | El cursor de GET /dtes no decodifica, viene alterado, o fue emitido con otro sort/dir — reintentar con el mismo token no lo arregla | fix_query |
dte.list.status_desconocido | 422 | sii_status trae un valor fuera del vocabulario del SII (message lista los válidos) — devolver 0 filas en silencio ocultaría un typo | fix_query |
dte.totales.query_invalid | 400 | El periodo de GET /dtes/totales no tiene formato YYYY-MM — quítalo para el mes en curso | — |
pending_action_not_found | 404 | No existe una solicitud pendiente con ese id en esta empresa. El id es el pending_id del 202 que devolvió tu pedido; una solicitud resuelta hace mucho puede haberse borrado por retención | retry_original_request |
pdf_url.not_configured | 503 | El entorno no tiene configurada la firma de enlaces de PDF (DTE_PDF_URL_SECRET) — no es un problema de tu documento | — |
document.not_found | 404 | El documento no existe, es de otra org, o el id no es un UUID. Las compras del RCV tampoco son reusables como plantilla y responden lo mismo: no se filtra cuál de las razones fue | — |
document.not_templatable | 422 | Solo las facturas 33/34 admiten reusarse como plantilla | — |
dte.list.tipo_invalido | 422 | tipo_dte no es el código numérico de un documento (33, 52, 61…) — devolver la lista sin filtrar por un typo es indistinguible de "no tienes documentos de ese tipo" | fix_query |
dte.list.folio_invalido | 422 | folio no es un entero de hasta 10 dígitos — más allá de ese largo la conversión perdería precisión y buscaría otro folio | fix_query |
dte.list.rut_receptor_invalido | 422 | rut_receptor no tiene forma de RUT (acepta puntos, espacios y k minúscula; el dígito verificador no se valida) | fix_query |
dte.list.fecha_invalida | 422 | fecha_emision_desde/fecha_emision_hasta no son YYYY-MM-DD | fix_query |
dte.list.polled_since_invalido | 422 | polled_since no es un instante ISO-8601 | fix_query |
dte.list.receptor_estado_invalido | 422 | receptor_estado no es uno de los cinco del vocabulario (reclamado, aceptado, en_plazo, aceptado_tacito, sin_info) — son los mismos que publica cada fila | fix_query |
dte.refresh_status.no_track_id | 409 | El DTE aún no fue subido al SII — no hay track_id que consultar | wait_for_emit_workflow |
dte.refresh_status.no_cert | 409 | La org no tiene certificado activo para autenticar la consulta de estado | — |
dte.resend_delivery.not_wired | 501 | El reenvío del DTE al receptor no está disponible en este entorno | — |
dte.resend_delivery.tipo_not_supported | 422 | El tipo_dte no se envía al receptor (las boletas 39/41 van a consumidores por el pipeline REST) | no_action |
dte.resend_delivery.no_email | 422 | El DTE no tiene correo del receptor — incluye correo_receptor en el body para reenviar | provide_correo_receptor |
dte.resend_delivery.no_aplica_cert | 422 | DTE de certificación cuya única dirección es la casilla de intercambio del SII, que no recibe documentos de prueba — incluye correo_receptor para mandárselo a una persona | provide_correo_receptor |
dte.resend_delivery.importado_no_reenviable | 422 | El documento se importó del Respaldo del SII: Notta no lo emitió ni lo envió, así que no puede reenviarlo — descarga el PDF o el XML y mándalo por otro canal | download_pdf_or_xml |
Muestras impresas (certificación)
| Código | HTTP | Descripción | next_action |
|---|---|---|---|
dte.muestras.empty | 422 | No hay DTEs firmados (33/34/56/61) para armar el lote de muestras | emit_and_sign_dtes_first |
dte.muestras.no_samples | 422 | No hay DTEs firmados para enviar como muestras al SII | emit_and_sign_dtes_first |
dte.muestras.too_large | 422 | El lote supera el límite de 3 MB del SII | paginate_into_multiple_emails |
dte.muestras.send_not_configured | 422 | El remitente de email no está configurado en el servidor | contact_support |
dte.muestras.not_sent | 422 | El envío no salió por una razón no mapeada — message trae el motivo | — |
dte.muestras.send_not_wired | 501 | El envío de muestras no está disponible en este entorno | — |
Certificado y folios (CAF) en la emisión
| Código | HTTP | Descripción | next_action |
|---|---|---|---|
cert.missing | 412 | Tu organización no tiene un certificado digital activo. Lo pide POST /caf/request antes de timbrar (el SII no firma la solicitud sin él) y el wizard de postulación | upload_certificate |
cert_not_found | 404 | No hay certificado digital cargado para la org | — |
cert_expired | 422 | Certificado expirado (detail.expiredAt) | — |
cert_subject_mismatch | 422 | El RUT del certificado no corresponde al emisor | — |
cert.kms.auth_failed | 422 | Falló el descifrado del certificado (detail.phase) — rotación de KEK o seed inconsistente | reseed_certificate |
caf_not_found | 404 | No hay CAF cargado para ese tipo de DTE (detail.tipoDte) | — |
caf_expired | 422 | CAF vencido (detail.expiredAt) | upload_caf |
caf_exhausted | 422 | CAF sin folios disponibles (detail.nextFolio) | upload_caf |
sii_env_mismatch | 422 | El CAF corresponde a otro ambiente SII (certificación vs producción) que el del DTE | — |
dte.production_resolucion_missing | 409 | Falta la Resolución Exenta del SII (NroResol/FchResol) para emitir a producción — se ingiere del email del SII a la casilla del emisor | capture_sii_resolucion |
dte.46.prod_not_certified | 422 | Tu organización no tiene el DTE 46 (Factura de Compra) autorizado para producción. Es el mismo gate por tipo de dte.type.prod_not_certified, con código propio por compatibilidad | emit_dte_46_in_cert |
Gestión de certificados (/certificates)
| Código | HTTP | Descripción | next_action |
|---|---|---|---|
cert.invalid_request | 400 | Falta file, password o label en el form-data | — |
cert.invalid | 422 | No se pudo leer el .p12 (corrupto, sin llave privada, o clave equivocada) | — |
cert.duplicate | 409 | Ese certificado (misma huella SHA-256) ya está cargado para la org | — |
cert.not_found | 404 | El certificado no existe para la org | — |
cert.expired | 409 | El certificado está vencido; no puede quedar como predeterminado | — |
cert.last_remaining | 409 | Es el único certificado de la org y borrarlo la dejaría sin firma para timbrar, emitir o enviar al SII. Para rotar: sube el reemplazo y recién después elimina el anterior | upload_certificate |
Gestión de CAF (/caf)
| Código | HTTP | Descripción | next_action |
|---|---|---|---|
caf.invalid_request | 400 | Falta file en el form-data | — |
caf.parse_error | 422 | El XML del CAF no trae los campos requeridos (RE/TD/D/H) | — |
caf.wrong_tipo | 422 | El CAF subido no corresponde al tipo_esperado del recuadro | — |
caf.no_certificate | 422 | No hay certificado cargado — sube el certificado antes del CAF | — |
caf.duplicate | 409 | Ese rango de folios ya está registrado | — |
caf.not_found | 404 | El CAF no existe para la org | — |
caf.has_accepted_dtes | 409 | No se puede eliminar: tiene DTEs aceptados por el SII (retención legal de 6 años) | — |
caf.has_ceded_dtes | 409 | No se puede eliminar: un DTE del CAF fue cedido vía RPETC | — |
caf.request_in_flight | 409 | Ya hay una solicitud reciente de folios para este tipo — espera unos minutos antes de reintentar | — |
caf.request_failed | 502 | La solicitud de folios al SII falló — message trae el motivo | — |
caf.grant_rejected | 502 | El SII no concedió el folio (rechazo del timbraje) — message/data traen el detalle | — |
caf.cert_not_authorized | 502 | El certificado activo no está autorizado a solicitar folios (timbrar) para esta empresa en el SII — revisa los usuarios autorizados en Mi SII o cambia el certificado activo | — |
caf.type_not_prod_certified | 409 | Tu organización no tiene ese tipo de documento autorizado para producción, así que no se pueden solicitar folios de producción para él | — |
caf.auto_requires_production | 409 | El timbraje automático (PUT /caf/auto) solo se activa con la empresa autorizada en producción; en certificación el proceso lo conduce la Puesta en Marcha | — |
Situación tributaria de la organización y solicitud de acceso
Estos códigos no vienen de un documento: vienen del RUT de la organización, o de quién puede operarla. Ninguno se arregla reintentando.
| Código | HTTP | Descripción | next_action |
|---|---|---|---|
situacion_tributaria.bloqueada | 409 | El SII confirmó que este RUT todavía no puede emitir: no existe en el SII, o no registra inicio de actividades. El campo estado del cuerpo dice cuál de los dos (rut_inexistente | sin_inicio_actividades). Lo responden seis entradas, y no todas significan lo mismo: POST /organizations lo responde ANTES de crear nada — el RUT de una organización es inmutable, así que no queda ninguna fila que arreglar, hay que volver a mandar el POST con el RUT corregido. Las otras cinco (POST /certificates, POST /onboarding/target-types, cualquier mutación bajo /onboarding/*, POST /organizations/me/sii-system y POST /organizations/me/onboarding-mode) actúan sobre una organización que YA existe y sólo quedó bloqueada — ahí sí hay que resolverlo en el SII y revalidar (POST /organizations/me/revalidar-situacion). Subir otro certificado o reintentar no cambia nada en ninguno de los dos casos | — |
situacion_tributaria.rate_limit | 429 | Demasiadas consultas de situación tributaria seguidas para el mismo usuario. El freno tiene dos ejes: volumen por minuto y una sola consulta en vuelo a la vez — el SII frena por conexiones, no por requests. retry_after_seconds trae la espera mínima | — |
invalid_rut | 400 | El RUT enviado a POST /organizations/solicitar-acceso no pasa el dígito verificador. Es el único endpoint con código propio para esto; en el resto un RUT inválido responde validation_failed | — |
access_request.rate_limit | 429 | Alcanzaste el máximo de solicitudes de acceso por hora. Se cuenta por solicitante, no por organización: pedir acceso a RUTs distintos consume el mismo cupo | — |
access_request.not_found | 404 | El token del enlace de decisión no corresponde a ninguna solicitud. Lo emite POST /organizations/solicitudes-acceso/decidir, un endpoint público y sin credenciales —el dueño abre el enlace del correo donde sea, el token es la única prueba—, así que este 404 también responde a un token inventado | — |
access_request.expired | 410 | La solicitud de acceso caducó (7 días sin decidirse) o la organización destino ya no existe. No se puede revivir: hay que volver a pedir acceso | — |
Notas de crédito y débito (compliance)
| Código | HTTP | Descripción | next_action |
|---|---|---|---|
dte.nota_credito.fuera_plazo | 422 | NC fuera del plazo legal de 6 meses (Ley 21.398) | consult_lawyer_or_use_correction_path |
nc.over_cedida.blocked | 422 | Factura referenciada cedida vía RPETC con aceptación irrevocable ≥8 días (Corte Suprema 2025) | confirm_override_and_retry |
dte.nota_credito.cedida_override_required | 409 | Mismo bloqueo de cesión, detectado por el chequeo de emisión: requiere override explícito | confirm_override_and_retry |
dte.nota_credito.invalid_cod_ref | 422 | cod_ref inválido para NC — usa 1 (anula), 2 (corrige texto), 3 (corrige montos) | fix_cod_ref_and_retry |
dte.nota_credito.reference_tipo_unsupported | 422 | NC 61 solo referencia Factura 33, Factura Exenta 34 o Factura de Compra 46 | use_factura_33_or_34_reference |
dte.nota_credito.plazo_anulacion_override_required | 409 | La NC que ANULA debía emitirse en el mismo período tributario o el siguiente (Res. Ex. SII 45/2003). Fuera de plazo el SII la acepta igual, pero el IVA se recupera por petición administrativa: reintenta con override_plazo_anulacion | confirm_override_and_retry |
dte.nota_credito.invalid_reason | 422 | nc_reason fuera del catálogo, o incoherente con el cod_ref de la referencia | fix_reason_and_retry |
dte.nota_debito.interese_moratorio_legal | 422 | Intereses moratorios legales no se documentan con DTE (Oficio SII 2011/2020) | consult_oficio_2011_2020 |
dte.nota_debito.invalid_reason | 422 | nd_reason fuera del enum válido (detail.validReasons) | fix_reason_and_retry |
dte.nota_debito.reference_tipo_unsupported | 422 | ND 56 solo referencia Factura 33, Factura Exenta 34, Factura de Compra 46 o Nota de Crédito 61 | use_supported_reference_tipo |
dte.reference.single_required | 422 | Anular (cod_ref 1) o corregir texto (cod_ref 2) admite un único documento de referencia (Formato DTE v2.5 §E); solo corregir montos (3) admite varios | split_into_one_note_per_document |
dte.reference.cross_env | 422 | El folio referenciado no existe en el ambiente de emisión, pero sí en el otro: certificación y producción llevan folios independientes | emit_in_the_same_sii_env |
Guía de despacho (52)
| Código | HTTP | Descripción | next_action |
|---|---|---|---|
dte.52.dispatch_required | 400 | DTE 52 requiere el bloque despacho | include_despacho_and_retry |
dte.52.invalid_traslado | 422 | ind_traslado fuera de los valores soportados (detail.supported) | fix_ind_traslado_and_retry |
dte.52.transportista_required | 422 | Falta el transportista (detail.field) — Res. 154/2025 | — |
dte.52.conductor_required | 422 | Falta el conductor (detail.field) — Res. 154/2025 | — |
dte.52.vehiculo_required | 422 | Falta el vehículo (detail.field) — Res. 154/2025 | — |
dte.52.parent_invalid | 500 | Inconsistencia interna con el documento padre referenciado | — |
guia.tipo_invalido | 409 | El documento no es una Guía (detail.tipoDte ≠ 52): esta vía anula solo el tipo 52 — para una factura, emite una Nota de Crédito (61) | use_nota_credito_para_factura |
guia.ya_facturada | 409 | La Guía (detail.folio) ya fue facturada: una Factura la referencia, así que no se puede anular sola | anula_la_factura_via_nota_credito |
SII y errores transitorios
| Código | HTTP | Descripción | next_action |
|---|---|---|---|
sii_rejection | 422 | El SII rechazó el DTE — detail.code y detail.glosa traen el veredicto | — |
sii_unavailable | 503 | SII caído transitorio (detail.retryAfterSec) | — |
sii_invalid_track_id | 502 | El SII no reconoce el track id del envío | — |
dte.tipo_cambio_unavailable | 503 | Solo exportación (110/112): la fuente de tipo de cambio no respondió. El documento no se emitió y no se usó folio, así que reintentar con la misma Idempotency-Key es seguro. Si la moneda no tiene fuente, el rechazo llega antes como validation_failed | retry_later |
rate_limit | 429 | Límite de tasa superado (detail.retryAfterSec) — ver Límites de tasa | — |
internal_error | 500 | Error no mapeado; el detalle queda en los logs del servidor | — |
empresa.not_found | 404 | No hay una empresa con ese id en el padrón de tu organización (GET /sii/empresas/{id}) | — |
empresa.conflict | 409 | Ya existe una empresa con ese RUT en tu padrón — edítala en vez de crearla | — |
shopify.cert_not_found | 404 | La instalación de la app de Shopify referencia un certificate_id que no existe en esa organización | — |
shopify.cert_rut_mismatch | 422 | El rut_emisor de la instalación de Shopify no coincide con el titular del certificado | — |
Recepción de compras — acuses y reclamos (/recepcion)
Registrar un acuse o un reclamo va ante el SII por SOAP y le avisa a tu proveedor: sus rechazos son del SII, no de Notta.
| Código | HTTP | Descripción | next_action |
|---|---|---|---|
recepcion.query_invalid | 400 | page y pageSize deben ser enteros, con pageSize entre 1 y 500 | — |
recepcion.no_encontrado | 404 | No hay un documento recibido con ese id en tu organización | — |
recepcion.evento_invalid_input | 400 | accion no es una de las que el registro admite — el message lista las válidas | — |
recepcion.rar_tipo_no_soportado | 422 | El SII no registra acuses ni reclamos para ese tipo de documento (tipoDte dice cuál era) | — |
recepcion.rar_evento_rechazado | 422 | El SII rechazó el registro. codResp es su código y detail su glosa — el veredicto es del SII | — |
recepcion.rar_cedible_warning | 409 | El documento es cedible y el reclamo puede afectar una cesión: el SII advierte antes de registrarlo. Trae requiresOverride: true; para seguir, el pedido debe volver con la confirmación explícita | — |
mcp_rate_limited | 429 | Se superó el tope de acciones que una conexión MCP puede registrar en el SII. retry_after_seconds y el header Retry-After dicen cuánto esperar | — |
Boletas
| Código | HTTP | Descripción | next_action |
|---|---|---|---|
boleta.credentials.not_found | 404 | Falta la clave tributaria SII de la org | configure_sii_credentials |
boleta.rest.unavailable | 502 | Endpoint REST de boletas del SII no disponible (detail.retryAfterSec) | retry_with_backoff |
boleta.rest.token_expired | 401 | Token del pipeline REST expirado | reauthenticate |
boleta.rest.pipeline_error | 500 | El pipeline REST falló en una fase interna (detail.phase) | operator_review |
boleta.xml.not_yet_available | 404 | La boleta todavía no tiene XML — el pipeline sigue corriendo | poll_self |
validation_error | 422 | Un campo del body no pasa el schema. En POST /dtes/{id}/resend-delivery es el correo_receptor; en el batch de boletas, el payload — ahí el detalle viene en errors[] | — |
boleta.batch.exceeds_max | 422 | El batch supera el máximo (detail.max) | split_batch |
boleta.batch.idempotency_conflict | 409 | Posición del batch ya ocupada (detail.batchId) | poll_existing_or_change_key |
boleta.batch.not_found | 404 | El batchId no existe para la org | verify_batch_id |
BHE
| Código | HTTP | Descripción | next_action |
|---|---|---|---|
bhe.credential.invalid | 401 | Clave tributaria BHE no encontrada o rechazada (detail.reason) | configure_bhe_credential |
bhe.plazo_anulacion.expired | 422 | BHE fuera del plazo de 3 meses para anular | consult_sii_or_manual_rectification |
bhe.retencion.mismatch | 422 | La retención enviada no concuerda con la tasa legal del año (detail.expected) | use_calculated_retencion |
bhe.receptor.tipo_invalid | 422 | Tipo de receptor inválido para BHE | fix_receptor_and_retry |
bhe.rest.unavailable | 502 | Endpoint BHE del SII (loa.sii.cl) no disponible (detail.retryAfterSec) | retry_with_backoff |
bhe.rest.token_expired | 401 | Token del pipeline BHE expirado | reauthenticate |
bhe.rest.pipeline_error | 500 | El pipeline BHE falló en una fase interna (detail.phase) | operator_review |
bhe.not_found | 404 | La BHE no existe para la org | — |
Billing
| Código | HTTP | Descripción | next_action |
|---|---|---|---|
billing.free_tier_exceeded | 402 | Cuota mensual del plan alcanzada (detail.usedThisMonth / detail.limit) — suscríbete a un plan superior o espera al próximo período | upgrade_plan |
Infraestructura (transitorios del servidor)
Reintenta con backoff; si persisten, contacta soporte con el request_id.
| Código | HTTP | Descripción | next_action |
|---|---|---|---|
db.unavailable | 503 | La base de datos no está disponible | — |
db.pool_exhausted | 503 | El pool de conexiones a la base de datos está saturado — reintenta | — |
cert.kms_unavailable | 503 | El KMS que cifra certificados no está disponible | — |
caf.kms_unavailable | 503 | El KMS que cifra CAFs no está disponible | — |
cert.insert_failed | 500 | Falló la persistencia del certificado | — |
caf.insert_failed | 500 | Falló la persistencia del CAF | — |
RCV y RCOF
| Código | HTTP | Descripción | next_action |
|---|---|---|---|
rcv.sync.failed | 502 | El sync del RCV falló contra el SII (detail.periodo) | retry_sync |
rcv.unauthorized | 401 | Certificado digital rechazado por el SII para RCV | configure_sii_credential |
rcv.period.invalid | 422 | Periodo inválido — debe ser YYYY-MM y no estar en el futuro (detail.reason) | fix_period_and_retry |
rcof.no_data | 422 | Sin boletas 39/41 emitidas en esa fecha — no se genera RCOF (detail.fecha) | verify_fecha |
rcof.aggregation_error | 500 | Falló la agregación de boletas del día para el RCOF | — |
rcof.build_error | 500 | Falló la construcción del XML del RCOF | — |
rcof.upload_error | 502 | El envío del RCOF al SII falló (detail.phase) | retry_resend |
rcv.not_found | 404 | No hay snapshot del RCV para ese período — hay que sincronizarlo primero con POST /rcv | sync_first |
rcv.query.invalid | 422 | Falta o es inválido `?type=issued | received (issuedson tus ventas;received`, tus compras) |
rcv.cursor.invalid | 422 | El cursor no decodifica — usa el next_cursor de la respuesta anterior sin modificarlo | fix_query |
rcv.input.invalid | 422 | El cuerpo de POST /rcv no valida — debe ser {rut, periodo, type?, force?} | fix_input |
Webhooks salientes (/webhooks)
| Código | HTTP | Descripción | next_action |
|---|---|---|---|
invalid_webhook_url | 422 | La URL de callback no es https pública: apunta a localhost, a un rango privado, al servicio de metadata de la nube o trae un puerto propio. Se revisa al registrar y en cada entrega, así que un dominio que empiece a resolver a una IP privada deja de recibir | use_public_https_url |
webhook_endpoint_disabled | 409 | POST /webhooks/{id}/test sobre una suscripción apagada (active: false): no se encola nada. El porqué viaja en detail.disabled_reason. Una suscripción apagada no se reactiva: bórrala y regístrala de nuevo, y despliega el secret nuevo en tu verificador | recreate_webhook_endpoint |
Los demás códigos de /webhooks son los comunes: idempotency_key_missing y invalid_json (400), unauthorized (401), forbidden si a la API key le falta webhook:read o webhook:write (403), validation_failed si la url o los events no cumplen el schema (422), y not_found si el id no existe, es de otra empresa o es del otro ambiente (404).
Ejemplo: factura cedida
Rechazos del SII (al subir el DTE)
Cuando el SII recibe el EnvioDTE corre una cascada de validadores: XSD → schema → firma → carátula → timbre. Cada validador enmascara al siguiente, así que corregir un rechazo suele destapar el próximo en ese mismo orden.
El getEstUp del SII devuelve solo el código de cabecera (RFR/RCT/EPR); el sub-código accionable (p. ej. CRT-3-19, TED-2-510) llega por email del SII. Notta lo expone en sii_glosa.
| Rechazo | Significado | Acción |
|---|---|---|
RFR | Rechazado por Error en Firma (canonicalización c14n / xmlns heredado / charset de la firma) | Re-firmar el DTE con la canonicalización y el encoding correctos |
CHR-00002 | Línea muy larga o encoding latin1 — aflora como RFR/RSC | Corregir el encoding/largo de línea y re-firmar |
RCT | Rechazado por Error en Carátula | Corregir la Carátula y reenviar |
CRT-3-19 | Sub-código de RCT: Fecha/Número de Resolución inválido (FchResol/NroResol) | Corregir la resolución y reenviar |
TED-2-510 | Reparo: Firma del Timbre Electrónico (TED/FRMT) incorrecta — el DTE queda en EPR con reparo | Re-firmar el timbre sobre el DD canónico y reenviar |
RFR — Rechazado por Error en Firma
La firma se rompió porque los bytes canónicos que el SII verifica no son los que se firmaron: un xmlns heredado que el c14n omite al firmar e incluye al verificar, o un XML re-serializado después de firmar.
Cómo verificarlo: ejecuta un roundtrip local de firma + verificación sobre los bytes exactos que van al wire. Si el elemento firmado (SetDTE/Documento) solo hereda el namespace sin declararlo, el self-verify falla — redeclara xmlns explícito y firma con c14n-20010315 (el c14n exclusivo lo rechaza el XSD del SII).
CHR-00002 — línea muy larga o charset inválido
El validador de charset cortó el envío porque alguna línea del XML supera los 4090 caracteres o los bytes no van en ISO-8859-1.
Cómo verificarlo: mide el largo de línea máximo del XML enviado y confirma que el wire va como latin1, con saltos de línea entre las secciones mayores (Encabezado, Detalle, TED).
RCT — Rechazado por Error en Carátula
La carátula declara datos que el SII no tiene registrados para el emisor: RutEmisor/RutEnvia que no corresponden, o una resolución (FchResol/NroResol) inválida.
Cómo verificarlo: el sub-código del email del SII apunta al campo exacto (p. ej. CRT-3-19 es la resolución). Compara cada campo de la carátula contra lo registrado para la empresa en el SII antes de reenviar.
CRT-3-19 — Fecha/Número de Resolución inválido
La FchResol no es la fecha que el SII tiene registrada para tu empresa: en certificación el comodín 2014-08-22 no sirve para empresas recién postuladas — el SII espera la fecha real de postulación.
Cómo verificarlo: reenvía con FchResol = fecha en que la empresa postuló como emisor electrónico en maullin y NroResol = 0 (válido para todo emisor en certificación). Si el envío pasa, el comodín era el problema.
TED-2-510 — firma del timbre incorrecta
La firma FRMT se calculó sobre los bytes literales del DD, pero el SII la verifica sobre el DD canónico con el whitespace entre elementos colapsado.
Cómo verificarlo: verifica la FRMT localmente contra la clave pública del CAF usando dd.replace(/>\s+</g, "><") como input. Si verifica con la forma canónica y falla con la literal, re-firma el timbre sobre la canónica (preservando los bytes literales del CAF en el wire).
Corrección automática
Notta corrige la mayoría de estos rechazos automáticamente; este catálogo te ayuda a entender el sii_glosa cuando un DTE queda en un estado de rechazo.
Cómo manejar errores en código
Buenas prácticas
- Decide por
error.code(ynext_actioncuando viene), nunca por string-matching delmessage: el texto puede cambiar, los códigos no. next_actiones enumerable y estable — los valores existentes no cambian de semántica; solo se agregan nuevos.- No reintentes los
4xxsalvo429: un400/422va a fallar igual hasta que corrijas el payload. Los502/503transitorios sí se reintentan con backoff. - Loguea el
request_idde cada respuesta en tu sistema —del headerX-Request-Id, que viene también en los 200—: acelera cualquier diagnóstico con soporte, y es lo único que permite investigar una respuesta exitosa pero sospechosa.
Próximos pasos
- Límites de tasa — el detalle del
429y el patrón de backoff para errores transitorios. - Referencia API de DTEs — los endpoints que emiten estos códigos.
- Nota de crédito (61) — el flujo completo detrás de
nc.over_cedida.blockedy el plazo de 6 meses. - Webhooks — el push firmado que te avisa de un rechazo sin que preguntes.
Última actualización