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 doc del error, cuando aplica
  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.

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
forbidden403La key no tiene el scope requerido (dte:read / dte:write)use_api_key_with_required_scope
cert_id_missing400Falta el header X-Cert-Id en un verbo que firmasend_cert_id_header
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)

Validación del payload

CódigoHTTPDescripciónnext_action
validation_failed400El body no pasa el schema — revisa issues[] campo por campofix_body_and_retry
invalid_json400El body no es JSON válidofix_json_body_and_retry
idempotency_key_missing400Falta el header Idempotency-Key (obligatorio en todo POST de emisión)send_idempotency_key_header
receptor_rut_invalid400RUT receptor con DV inválido
emisor_rut_mismatch422El rut_emisor del body no coincide con el RUT del certificado
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)
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.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_certified422El tipo de DTE aún no está certificado para producción (gate N1 por tipo); emítelo en certificación (maullin) mientras se completa la cert ante el SIIemit_dte_in_cert
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)
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.refresh_status.no_track_id409El DTE aún no fue subido al SII — no hay track_id que consultarwait_for_emit_workflow
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)
dte.resend_delivery.no_email422El DTE no tiene correo del receptor — incluye correo_receptor en el body para reenviarprovide_correo_receptor

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_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)
caf_exhausted422CAF sin folios disponibles
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_certified422DTE 46 (Factura de Compra) habilitado solo en certificación (maullin) — la certificación oficial del tipo 46 para producción está en cursoemit_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

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.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_certified409Este tipo de documento aún no está certificado para producción. Completa la certificación por-tipo antes de solicitar folios.

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 facturas 33 o 34use_factura_33_or_34_reference
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

Guía de despacho (52)

CódigoHTTPDescripciónnext_action
dte.52.dispatch_required400DTE 52 requiere el bloque despachoinclude_despacho_and_retry
dte.52.invalid_traslado422ind_traslado fuera de los valores soportados (detail.supported)fix_ind_traslado_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

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 reconoce el track id del envío
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

Boletas

CódigoHTTPDescripciónnext_action
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_error422El payload del batch de boletas no pasa el schema — revisa 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) — suscribite 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 y RCOF

CódigoHTTPDescripciónnext_action
rcv.sync.failed502El sync del RCV falló contra el SII (detail.periodo)retry_sync
rcv.unauthorized401Clave tributaria rechazada 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
rcof.no_data422Sin boletas 39/41 emitidas en esa fecha — no se genera RCOF (detail.fecha)verify_fecha
rcof.aggregation_error500Falló la agregación de boletas del día para el RCOF
rcof.build_error500Falló la construcción del XML del RCOF
rcof.upload_error502El envío del RCOF al SII falló (detail.phase)retry_resend

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 error en tu sistema: acelera cualquier diagnóstico con soporte.

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 contrato de eventos para reaccionar a rechazos sin polling.

Última actualización