Notta Docs

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

type ErrorResponse = {
  code: string;          // "nc.over_cedida.blocked"
  message: string;       // human-readable
  request_id: string;    // siempre presente — UUID por request
  hint?: string;         // fix sugerido
  next_action?: string;  // enum estable: "confirm_override_and_retry" | "retry_with_backoff" | ...
  detail?: Record<string, unknown>; // campos públicos del error, p. ej. { "retryAfterSec": 30 }
  docs_url?: string;     // link a la fila de ESTE código en el catálogo de abajo
  issues?: unknown[];    // solo en validation_failed — issues Zod con path + message por campo
};

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ódigoHTTPDescripciónnext_action
unauthorized401Falta el header Authorization: Bearersend_bearer_token
invalid_api_key401La API key no matchea ninguna key activaregenerate_api_key
api_key_expired401API key expiradaregenerate_api_key
api_key_revoked401API key revocadaregenerate_api_key
forbidden403Dos 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 ayudause_api_key_with_required_scope (solo en el de scope)
cert_id_missing400La org no tiene ningún certificado cargado y el verbo firmaupload_certificate
cert_id_ambiguous400La org tiene varios certificados vigentes — especifica cuál firma con X-Cert-Idsend_cert_id_header
org.required412La sesión de dashboard no tiene organización — completa el onboarding de org (aplica a /certificates, /caf y /api-keys)—
org.rut_missing412La organización de la sesión no tiene RUT registrado — complétalo en el onboarding antes de sincronizar el RCV—
onboarding_production_not_authorized403La org todavía no está habilitada para emitir en producción (palena)—
csrf_origin_mismatch403Origin no permitido para esta acción (protección CSRF de la sesión de dashboard; no aplica al camino Authorization: Bearer)—
csrf_blocked403Variante 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ódigoHTTPDescripciónnext_action
validation_failed400El 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_json400El body no es JSON válidofix_json_body_and_retry
invalid_action400El campo action de POST /dtes/{id}/derive no está en el enum (copy, anular, corregir-nc, corregir-nd, corregir-texto), o el body no tiene esa forma, o pide una opción que ese documento no admite (el message dice cuál). Este endpoint responde con code y message solamente: no trae issues[] ni next_action—
idempotency_key_missing400Falta el header Idempotency-Key (obligatorio en todo POST de emisión)send_idempotency_key_header
idempotency_key_reused409Esa 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 originaluse_new_idempotency_key
emisor_rut_mismatch422El rut_emisor del body no corresponde a la empresa de tu cuenta (la de la API key o la sesión). Se compara con la empresa, no con el titular del certificado, que en una sociedad es una persona. No se asignó folio ni se creó nada—
emisor.profile_incompleto422Faltan datos del perfil del emisor para emitir (detail.missing)complete_emisor_profile
items_empty400items vacío—
items_exceed_max400items supera el máximo (límite SII; detail.count)—
dte.print.items_limit422El nuevo documento supera el máximo de 40 ítems (detail.count). No se asignó folio ni se consumió cuota.Divide los ítems en dos documentos.
dte.print.overflow422El contenido completo no cabe en una hoja por copia, después de intentar carta y oficio y compactar hasta 8 puntos. No se emitió el documento.Acorta las glosas o divide los ítems en dos documentos.
dte.print.measurement_failed503No se pudo medir el PDF; la emisión se detuvo antes del folio y de la cuota.Conserva el borrador y reintenta en unos minutos.
dte.sucursal.not_found422El sucursal_id de la emisión no es una sucursal vigente de tu empresa: no existe, la borraste o es de otra empresa (detail.sucursalId). No se asignó folio ni se consumió cuota. Revisa las sucursales vigentes con GET /sucursales y usa el id de la sucursal desde la que emitescheck_sucursal_id
amount_arithmetic400Los montos declarados no cuadran aritméticamente—
references_required400El tipo_dte exige references y no vienen—
reference_invalid_cod_ref400cod_ref fuera del enum 1/2/3—
text_correction_must_be_zero400NC de corrección de texto (cod_ref 2) debe llevar montos en cero—
dte.tipo_not_supported400tipo_dte no soportado por este pipelinefix_tipo_dte_and_retry
dte.preview.unsupported_tipo422La vista previa no cubre ese tipo_dte. POST /dtes/preview acepta 33, 34, 46, 52, 56 y 61: fuera de esa lista quedan los tipos cuyo borrador no se puede revisar ni promover. El hint lista los tipos vigentesuse_supported_tipo_dte
dte.34.invalid_exenta422DTE 34 (Factura Exenta) con items afectosfix_tipo_dte_and_retry
dte.41.afecto_not_allowed422Boleta Exenta 41 con items afectosfix_tipo_dte_and_retry
dte.46.invalid_afecta422DTE 46 (Factura de Compra) con items exentos — es una operación 100% afecta (cambio de sujeto)remove_exento_items_and_retry
dte.mixed_retencion_references422Una 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 documentosplit_into_separate_documents_by_retencion
dte.type.prod_not_certified422Tu 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 revisarlocontact_support_to_enable_type
dte.sii_env_credential_mismatch422El 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 ambienteuse_api_key_matching_sii_env
dte.field_too_long422Un campo supera el maxLength que exige el XSD del SII (detail trae field, element, maxLength, actualLength) — atrapado antes de firmar, sin quemar folioshorten_field_and_retry
dte.field_not_latin1422Un campo trae un carácter que el SII no puede escribir y que NO tiene equivalente, típicamente un emoji o un ideograma (detail trae field, element, char, codepoint, index). El XML del DTE va en ISO-8859-1. No hace falta que sanees tu texto: los acentos y la ñ se pueden usar tal cual, y la tipografía sin contenido (raya larga —, comillas curvas, puntos suspensivos, espacios de ancho cero) la sustituye el servidor por su equivalente antes de emitir. Atrapado antes de firmar, sin quemar foliofix_field_encoding_and_retry
idempotency_conflict409Mismo Idempotency-Key con otro body — detail.existingDteId apunta al DTE original—

Lectura y estado del DTE

CódigoHTTPDescripciónnext_action
not_found404El 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. POST /rcof y POST /rcof/resend también responden not_found: se retiraron porque el RCOF dejó de ser obligatorio el 1 de agosto de 2022 (Res. Ex. SII N°53) y Notta ya no lo envía al SII; no reintentes—
dte.xml.not_yet_available404El DTE todavía no tiene XML — el workflow de firma sigue corriendopoll_self
dte.pdf.not_signed409El DTE existe pero no está firmado — el PDF requiere el TED (síguelo en xml_url)poll_self
dte.list.cursor_invalido422El cursor de GET /dtes no decodifica, viene alterado, o fue emitido con otro sort/dir — reintentar con el mismo token no lo arreglafix_query
dte.list.status_desconocido422sii_status trae un valor fuera del vocabulario del SII (message lista los válidos) — devolver 0 filas en silencio ocultaría un typofix_query
dte.totales.query_invalid400El periodo de GET /dtes/totales no tiene formato YYYY-MM — quítalo para el mes en curso—
pending_action_not_found404No 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ónretry_original_request
pdf_url.not_configured503El entorno no tiene configurada la firma de enlaces de PDF (DTE_PDF_URL_SECRET) — no es un problema de tu documento—
document.not_found404El 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_templatable422Solo las facturas 33/34 admiten reusarse como plantilla—
dte.list.tipo_invalido422tipo_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_invalido422folio 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 foliofix_query
dte.list.rut_receptor_invalido422rut_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_invalida422fecha_emision_desde/fecha_emision_hasta no son YYYY-MM-DDfix_query
dte.list.polled_since_invalido422polled_since no es un instante ISO-8601fix_query
dte.list.receptor_estado_invalido422receptor_estado no es uno de los cinco del vocabulario (reclamado, aceptado, en_plazo, aceptado_tacito, sin_info) — son los mismos que publica cada filafix_query
dte.refresh_status.no_track_id409El DTE aún no fue subido al SII — no hay track_id que consultarwait_for_emit_workflow, o operator_review si el documento ya no está en proceso (emision_fallida, envio_repetido: no hay un envío en curso que esperar)
dte.refresh_status.no_cert409La org no tiene certificado activo para autenticar la consulta de estado—
dte.resend_delivery.not_wired501El reenvío del DTE al receptor no está disponible en este entorno—
dte.resend_delivery.tipo_not_supported422El 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_email422El DTE no tiene correo del receptor. Con API key, incluye correo_receptor en el body; por una conexión MCP la operación no admite cuerpo y la respuesta trae register_receptor_email, o sea registrar el correo en el catálogo de contrapartesprovide_correo_receptor
dte.resend_delivery.no_aplica_cert422DTE de certificación cuya única dirección es la casilla de intercambio del SII, que no recibe documentos de prueba. Con API key, incluye correo_receptor; por una conexión MCP la respuesta trae register_receptor_email y el correo se registra en el catálogo de contrapartesprovide_correo_receptor
dte.resend_delivery.importado_no_reenviable422El 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 canaldownload_pdf_or_xml

Muestras impresas (certificación)

CódigoHTTPDescripciónnext_action
dte.muestras.empty422No hay DTEs firmados (33/34/56/61) para armar el lote de muestrasemit_and_sign_dtes_first
dte.muestras.no_samples422No hay DTEs firmados para enviar como muestras al SIIemit_and_sign_dtes_first
dte.muestras.too_large422El lote supera el límite de 3 MB del SIIpaginate_into_multiple_emails
dte.muestras.send_not_configured422El remitente de email no está configurado en el servidorcontact_support
dte.muestras.not_sent422El envío no salió por una razón no mapeada — message trae el motivo—
dte.muestras.send_not_wired501El envío de muestras no está disponible en este entorno—

Certificado y folios (CAF) en la emisión

CódigoHTTPDescripciónnext_action
cert.missing412Tu 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ónupload_certificate
cert_not_found404No hay certificado digital cargado para la org—
cert_expired422Certificado expirado (detail.expiredAt)—
cert_subject_mismatch422El RUT del certificado no corresponde al emisor—
cert.kms.auth_failed422Falló el descifrado del certificado (detail.phase) — rotación de KEK o seed inconsistentereseed_certificate
caf_not_found404No hay CAF cargado para ese tipo de DTE (detail.tipoDte)—
caf_expired422CAF vencido (detail.expiredAt)upload_caf
caf_exhausted422CAF sin folios disponibles (detail.nextFolio)upload_caf
sii_env_mismatch422El CAF corresponde a otro ambiente SII (certificación vs producción) que el del DTE—
dte.production_resolucion_missing409Falta la Resolución Exenta del SII (NroResol/FchResol) para emitir a producción — se ingiere del email del SII a la casilla del emisorcapture_sii_resolucion
dte.46.prod_not_certified422Tu 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 compatibilidademit_dte_46_in_cert

Gestión de certificados (/certificates)

CódigoHTTPDescripciónnext_action
cert.invalid_request400Falta file, password o label en el form-data—
cert.invalid422No se pudo leer el .p12 (corrupto, sin llave privada, o clave equivocada)—
cert.duplicate409Ese certificado (misma huella SHA-256) ya está cargado para la org—
cert.not_found404El certificado no existe para la org—
cert.expired409El certificado está vencido; no puede quedar como predeterminado—
cert.last_remaining409Es 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 anteriorupload_certificate

Gestión de CAF (/caf)

CódigoHTTPDescripciónnext_action
caf.invalid_request400Falta file en el form-data—
caf.parse_error422El XML del CAF no trae los campos requeridos (RE/TD/D/H)—
caf.wrong_tipo422El CAF subido no corresponde al tipo_esperado del recuadro—
caf.no_certificate422No hay certificado cargado — sube el certificado antes del CAF—
caf.duplicate409Ese rango de folios ya está registrado—
caf.not_found404El CAF no existe para la org—
caf.has_accepted_dtes409No se puede eliminar: tiene DTEs aceptados por el SII (retención legal de 6 años)—
caf.has_ceded_dtes409No se puede eliminar: un DTE del CAF fue cedido vía RPETC—
caf.request_in_flight409Ya hay una solicitud reciente de folios para este tipo — espera unos minutos antes de reintentar—
caf.request_failed502La solicitud de folios al SII falló — message trae el motivo—
caf.grant_rejected502El SII no concedió el folio (rechazo del timbraje) — message/data traen el detalle—
caf.persist_failed502El SII otorgó el rango y Notta no pudo guardarlo. No vuelvas a solicitar: recupéralo en el portal del SII con "Reobtención de folios" y súbelo en /app/caf—
caf.cert_not_authorized502El 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_certified409Tu 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_production409El 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ódigoHTTPDescripciónnext_action
situacion_tributaria.bloqueada409El 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_limit429Demasiadas 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—
onboarding.autopilot_migrante_sin_activar409Pediste encender el piloto automático de certificación (autopilot: true en POST /onboarding/target-types) para una empresa que el SII ya autorizó como emisora y cuya emisión real en Notta está pendiente de activar. Esa empresa no pasa por la certificación, así que el piloto no tiene nada que hacer. El rechazo es completo: no se guardan los tipos ni cambia la fase. El camino es activar la emisión real, un paso que un owner o un admin confirma desde el navegador (app.notta.cl/onboarding/migracion/activar) y que no se puede hacer con API key; reintentar el mismo POST no cambia nada. Una empresa ya activada no recibe este código—
invalid_rut400El 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_limit429Alcanzaste 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_found404El 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.expired410La 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ódigoHTTPDescripciónnext_action
dte.nota_credito.fuera_plazo422NC fuera del plazo legal de 6 meses (Ley 21.398)consult_lawyer_or_use_correction_path
nc.over_cedida.blocked422Factura referenciada cedida vía RPETC con aceptación irrevocable ≥8 días (Corte Suprema 2025)confirm_override_and_retry
dte.nota_credito.cedida_override_required409Mismo bloqueo de cesión, detectado por el chequeo de emisión: requiere override explícitoconfirm_override_and_retry
dte.nota_credito.invalid_cod_ref422cod_ref inválido para NC — usa 1 (anula), 2 (corrige texto), 3 (corrige montos)fix_cod_ref_and_retry
dte.nota_credito.reference_tipo_unsupported422NC 61 solo referencia Factura 33, Factura Exenta 34 o Factura de Compra 46use_factura_33_or_34_reference
dte.nota_credito.plazo_anulacion_override_required409La 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_anulacionconfirm_override_and_retry
dte.nota_credito.invalid_reason422nc_reason fuera del catálogo, o incoherente con el cod_ref de la referenciafix_reason_and_retry
dte.nota_debito.interese_moratorio_legal422Intereses moratorios legales no se documentan con DTE (Oficio SII 2011/2020)consult_oficio_2011_2020
dte.nota_debito.invalid_reason422nd_reason fuera del enum válido (detail.validReasons)fix_reason_and_retry
dte.nota_debito.reference_tipo_unsupported422ND 56 solo referencia Factura 33, Factura Exenta 34, Factura de Compra 46 o Nota de Crédito 61use_supported_reference_tipo
dte.reference.single_required422Anular (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 variossplit_into_one_note_per_document
dte.reference.cross_env422El folio referenciado no existe en el ambiente de emisión, pero sí en el otro: certificación y producción llevan folios independientesemit_in_the_same_sii_env
nota_previa_override_required409El documento que quieres corregir YA tiene una nota que lo anula (cod_ref 1) o que le corrigió montos (cod_ref 3). Emitir otra lo acredita dos veces y el SII no lo impide: acepta las dos. El cuerpo trae nota_previa con la más reciente (tipo_dte, folio, fecha_emision, monto_total en PESOS CHILENOS, cod_ref y razon_ref), total_notas_previas, y cobertura: completa si Notta emitió el documento y sus notas, parcial si vino del Respaldo del SII y sólo conocemos los períodos importados (ahí "no encontramos otra" no equivale a "no existe"). No bloquea: si de verdad corresponde una segunda nota, reintenta con override_nota_previa: true—
importado_confirm_required409No encontramos ninguna nota previa, pero el documento se importó del Respaldo del SII y ahí la cobertura es PARCIAL: sólo alcanzamos los períodos que se importaron, que no son todos. Declara el límite de lo que sabemos, no que la nota no exista. Reintenta con override_nota_previa: true para asumirlo.—
cedida_override_required409El mismo bloqueo de cesión de nc.over_cedida.blocked, visto por POST /dtes/{id}/derive. Va sin prefijo porque la derivación reenvía el veredicto del servicio tal cual, sin pasar por el mapper que agrega el namespace dte.nota_credito.: el nombre que recibes en la derivación y el de la emisión (dte.nota_credito.cedida_override_required) son distintos aunque la causa sea la misma. Reintenta con override_cedida: true—
plazo_anulacion_override_required409Anular fuera del período tributario (Res. Ex. SII 45/2003), visto por POST /dtes/{id}/derive. El cuerpo trae plazo_vencio_el y days_overdue. Sin prefijo por el mismo motivo que cedida_override_required: en la emisión el nombre es dte.nota_credito.plazo_anulacion_override_required. Reintenta con override_plazo_anulacion: true—
fuera_plazo422La factura supera los 6 meses del plazo legal para la NC (Ley 21.398), visto por la derivación desde una venta del RCV. El cuerpo trae days_overdue. Aquí no hay override: es el mismo límite que en la emisión reporta dte.nota_credito.fuera_plazo—

Guía de despacho (52)

CódigoHTTPDescripciónnext_action
dte.52.dispatch_required400DTE 52 requiere el bloque despachoinclude_despacho_and_retry
dte.52.transportista_required422Falta el transportista (detail.field) — Res. 154/2025—
dte.52.conductor_required422Falta el conductor (detail.field) — Res. 154/2025—
dte.52.vehiculo_required422Falta el vehículo (detail.field) — Res. 154/2025—
dte.52.parent_invalid500Inconsistencia interna con el documento padre referenciado—
guia.tipo_invalido409El 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_facturada409La Guía (detail.folio) ya fue facturada: una Factura la referencia, así que no se puede anular solaanula_la_factura_via_nota_credito

SII y errores transitorios

CódigoHTTPDescripciónnext_action
sii_rejection422El SII rechazó el DTE — detail.code y detail.glosa traen el veredicto—
sii_unavailable503SII caído transitorio (detail.retryAfterSec)—
sii_invalid_track_id502El SII no devolvió un track id válido al recibir el envío—
dte.tipo_cambio_unavailable503Solo 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_failedretry_later
rate_limit429Límite de tasa superado (detail.retryAfterSec) — ver Límites de tasa—
internal_error500Error no mapeado; el detalle queda en los logs del servidor—
empresa.not_found404No hay una empresa con ese id en el padrón de tu organización (GET /sii/empresas/{id})—
empresa.conflict409Ya existe una empresa con ese RUT en tu padrón — edítala en vez de crearla—
empresa.correos_no_editable_por_mcp422Una conexión MCP mandó correos al crear o editar una contraparte. Ese campo decide a qué dirección le llega cada documento que le emitas, así que no se escribe por ese canal: no se creó ni se cambió nada. Reintenta el mismo cuerpo sin la clave (detail.campos los lista). Para cambiarlos, edita la contraparte en /app/empresas; con una API key clásica el campo sí se aceptaremove_correos_and_retry
shopify.cert_not_found404La instalación de la app de Shopify referencia un certificate_id que no existe en esa organización—

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ódigoHTTPDescripciónnext_action
recepcion.query_invalid400page y pageSize deben ser enteros, con pageSize entre 1 y 500—
recepcion.no_encontrado404No hay un documento recibido con ese id en tu organización—
recepcion.evento_invalid_input400accion no es una de las que el registro admite — el message lista las válidas—
recepcion.rar_tipo_no_soportado422El SII no registra acuses ni reclamos para ese tipo de documento (tipoDte dice cuál era)—
recepcion.rar_evento_rechazado422El SII rechazó el registro. codResp es su código y detail su glosa — el veredicto es del SII—
recepcion.rar_cedible_warning409El 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_limited429Se 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—

Conexiones MCP: topes por minuto

Sólo los reciben las conexiones MCP; una API key no pasa por estos topes. El tope lo fija cada empresa en /app/mcp ("Tope de acciones por minuto") y cada tipo de acción tiene su propio cupo, así que previsualizar no te deja sin emitir. Las respuestas exitosas traen RateLimit-Remaining: no hace falta chocar el tope para conocerlo.

CódigoHTTPDescripciónnext_action
mcp.emit_rate_limited429Se superó el tope de emisiones por minuto de las conexiones MCP. Cuenta los documentos emitidos y los que quedaron esperando aprobación. Retry-After dice cuánto esperar; reintenta el mismo documento con la misma Idempotency-Keywait_and_retry
mcp.emit_rate_limit_invalid429El tope de acciones por minuto de la empresa no tiene un valor válido, así que no se emitió nada. Lo corrige un owner o admin en /app/mcpfix_org_mcp_rate_limit
mcp.borrador_rate_limited429Se superó el tope de borradores por minuto de las conexiones MCP (POST /dtes/preview). No se guardó el borrador y no se emitió nadawait_and_retry
mcp.borrador_rate_limit_invalid429El tope de acciones por minuto de la empresa no tiene un valor válido, así que no se guardó ningún borrador. Lo corrige un owner o admin en /app/mcpfix_org_mcp_rate_limit
mcp.reenvio_rate_limited429Se superó el tope de reenvíos al receptor por minuto de las conexiones MCP (POST /dtes/{id}/resend-delivery). No se mandó ningún correo con esa llamadawait_and_retry
mcp.reenvio_rate_limit_invalid429El tope de acciones por minuto de la empresa no tiene un valor válido, así que no se reenvió nada. Lo corrige un owner o admin en /app/mcpfix_org_mcp_rate_limit

Boletas

CódigoHTTPDescripciónnext_action
boleta.tipo_no_habilitado422Tu organización no tiene habilitada la emisión de ese tipo de boleta. No se asignó folio ni se creó el documento: escríbenos para revisarlocontact_support_to_enable_type
boleta.credentials.not_found404Falta la clave tributaria SII de la orgconfigure_sii_credentials
boleta.rest.unavailable502Endpoint REST de boletas del SII no disponible (detail.retryAfterSec)retry_with_backoff
boleta.rest.token_expired401Token del pipeline REST expiradoreauthenticate
boleta.rest.pipeline_error500El pipeline REST falló en una fase interna (detail.phase)operator_review
boleta.xml.not_yet_available404La boleta todavía no tiene XML — el pipeline sigue corriendopoll_self
validation_error422Un 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_max422El batch supera el máximo (detail.max)split_batch
boleta.batch.idempotency_conflict409Posición del batch ya ocupada (detail.batchId)poll_existing_or_change_key
boleta.batch.not_found404El batchId no existe para la orgverify_batch_id

BHE

CódigoHTTPDescripciónnext_action
bhe.credential.invalid401Clave tributaria BHE no encontrada o rechazada (detail.reason)configure_bhe_credential
bhe.plazo_anulacion.expired422BHE fuera del plazo de 3 meses para anularconsult_sii_or_manual_rectification
bhe.retencion.mismatch422La retención enviada no concuerda con la tasa legal del año (detail.expected)use_calculated_retencion
bhe.receptor.tipo_invalid422Tipo de receptor inválido para BHEfix_receptor_and_retry
bhe.rest.unavailable502Endpoint BHE del SII (loa.sii.cl) no disponible (detail.retryAfterSec)retry_with_backoff
bhe.rest.token_expired401Token del pipeline BHE expiradoreauthenticate
bhe.rest.pipeline_error500El pipeline BHE falló en una fase interna (detail.phase)operator_review
bhe.not_found404La BHE no existe para la org—

Billing

CódigoHTTPDescripciónnext_action
billing.free_tier_exceeded402Cuota mensual del plan alcanzada (detail.usedThisMonth / detail.limit) — suscríbete a un plan superior o espera al próximo períodoupgrade_plan

Infraestructura (transitorios del servidor)

Reintenta con backoff; si persisten, contacta soporte con el request_id.

CódigoHTTPDescripciónnext_action
db.unavailable503La base de datos no está disponible—
db.pool_exhausted503El pool de conexiones a la base de datos está saturado — reintenta—
cert.kms_unavailable503El KMS que cifra certificados no está disponible—
caf.kms_unavailable503El KMS que cifra CAFs no está disponible—
cert.insert_failed500Falló la persistencia del certificado—
caf.insert_failed500Falló la persistencia del CAF—

RCV

CódigoHTTPDescripciónnext_action
rcv.sync.failed502El sync del RCV falló contra el SII (detail.periodo)retry_sync
rcv.unauthorized401Certificado digital rechazado por el SII para RCVconfigure_sii_credential
rcv.period.invalid422Periodo inválido — debe ser YYYY-MM y no estar en el futuro (detail.reason)fix_period_and_retry
rcv.not_found404No hay snapshot del RCV para ese período — hay que sincronizarlo primero con POST /rcvsync_first
rcv.query.invalid422Falta o es inválido `?type=issuedreceived (issuedson tus ventas;received`, tus compras)
rcv.cursor.invalid422El cursor no decodifica — usa el next_cursor de la respuesta anterior sin modificarlofix_query
rcv.input.invalid422El cuerpo de POST /rcv no valida — debe ser {rut, periodo, type?, force?}fix_input

Sucursales del SII (/sucursales)

CódigoHTTPDescripciónnext_action
sucursal.not_found404No hay una sucursal vigente con ese id en tu empresa: no existe, ya la borraste o es de otra empresa (PATCH o DELETE /sucursales/{id}). Revisa las vigentes con GET /sucursales; una sucursal borrada no se edita, se registra de nuevo—
sucursal.duplicada409Tu empresa ya tiene una sucursal vigente con ese código del SII (detail.cdgSiiSucur). No se creó ni se cambió nada. Si es la misma sucursal, edítala con PATCH /sucursales/{id}; el código lo entrega el SII en Mi SII, así que revisa que lo copiaste bien—

Webhooks salientes (/webhooks)

CódigoHTTPDescripciónnext_action
invalid_webhook_url422La 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 recibiruse_public_https_url
webhook_endpoint_disabled409POST /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 verificadorrecreate_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

{
  "code": "nc.over_cedida.blocked",
  "message": "NC inoponible al cesionario: la factura referenciada (folio 1234) tiene una cesión RPETC aceptada irrevocablemente (Doctrina Corte Suprema 2025).",
  "hint": "Factura cedida via RPETC con cesión irrevocable (≥8d). Set override_cedida=true en el body con respaldo operacional firmado.",
  "next_action": "confirm_override_and_retry",
  "detail": { "folioRef": 1234 },
  "request_id": "9f3b2c61-7d4a-4e0b-9c2d-1a5e8f3b7c90"
}

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.

RechazoSignificadoAcción
RFRRechazado 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-00002Línea muy larga o encoding latin1 — aflora como RFR/RSCCorregir el encoding/largo de línea y re-firmar
RCTRechazado por Error en CarátulaCorregir la Carátula y reenviar
CRT-3-19Sub-código de RCT: Fecha/Número de Resolución inválido (FchResol/NroResol)Corregir la resolución y reenviar
TED-2-510Reparo: Firma del Timbre Electrónico (TED/FRMT) incorrecta — el DTE queda en EPR con reparoRe-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

const res = await fetch("https://app.notta.cl/api/v1/dtes", { /* ... */ });
if (!res.ok) {
  const err = await res.json();
  switch (err.next_action) {
    case "retry_with_backoff": return retryLater(err.detail?.retryAfterSec);
    case "regenerate_api_key": return notifyOps(err);
    case "confirm_override_and_retry": return promptUser(err);
    default: throw new Error(`${err.code} (request_id: ${err.request_id})`);
  }
}

Buenas prácticas

  • Decide por error.code (y next_action cuando viene), nunca por string-matching del message: el texto puede cambiar, los códigos no.
  • next_action es enumerable y estable — los valores existentes no cambian de semántica; solo se agregan nuevos.
  • No reintentes los 4xx salvo 429: un 400/422 va a fallar igual hasta que corrijas el payload. Los 502/503 transitorios sí se reintentan con backoff.
  • Loguea el request_id de cada respuesta en tu sistema —del header X-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 429 y 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.blocked y el plazo de 6 meses.
  • Webhooks — el push firmado que te avisa de un rechazo sin que preguntes.

Última actualización