Estados del DTE
Todos los estados de un DTE con su categoría, cuál es terminal y qué hacer con cada uno, más la cadencia real del seguimiento ante el SII.
Emitir un DTE es asíncrono: POST /dtes responde 202 y el documento sigue
viajando. Esta página es la lista completa de los estados por los que pasa, qué
significa cada uno y cómo esperar el resultado sin escribir un bucle que no
termina nunca.
El bloque estado
Toda respuesta que trae sii_status trae también estado, el mismo valor ya
clasificado. sii_status no cambia y sigue siendo el contrato: estado se
agrega. Está en GET /dtes, GET /dtes/{id}, el 202 de POST /dtes y en las
tres respuestas de POST /dtes/{id}/refresh-status.
| Campo | Qué es |
|---|---|
code | El mismo valor de sii_status. Es un string, no un enum cerrado, ver El universo del SII es abierto. |
label | Glosa corta en español, para mostrar. |
descripcion | Qué pasó y qué significa, en prosa. |
terminal | true cuando el SII ya dio su veredicto sobre el documento. Es la condición de corte de cualquier espera. |
poll_activo | true cuando hay un seguimiento nuestro consultándole el estado al SII en este momento. |
categoria | Enum cerrado: en_proceso · aceptado · rechazado · requiere_accion · archivistico. |
accion | Enum cerrado: esperar · reintentar_consulta · reemitir · contactar_soporte · accion_en_sii · ninguna. |
categoria y accion son estables igual que el next_action de los errores:
están diseñados para que ramifiques por código, sin leer label ni descripcion.
Los estados
| Código | Qué significa | Terminal | Categoría | Acción |
|---|---|---|---|---|
queued | El documento se creó en Notta y está en cola para firmarse y subirse. Todavía no salió. | no | en_proceso | esperar |
sending | Notta está subiendo el documento al SII. Todavía no hay track_id. | no | en_proceso | esperar |
signed | El XML ya está firmado con tu certificado y todavía no se sube. Etapa interna de Notta. | no | en_proceso | esperar |
SOK | El SII validó el esquema del sobre. Etapa del envío, no un veredicto. | no | en_proceso | esperar |
CRT | El SII validó la carátula del sobre (los datos de tu resolución). Etapa del envío. | no | en_proceso | esperar |
FOK | El SII validó la firma electrónica del sobre. Etapa del envío. | no | en_proceso | esperar |
PDR | El SII tiene el envío en proceso y todavía no lo resolvió. | no | en_proceso | esperar |
PRD | El mismo estado que PDR: el instructivo del SII usa las dos grafías. | no | en_proceso | esperar |
-11 | La consulta de estado falla porque el SII todavía no registra el envío recién subido. Transitorio, y es el camino normal. | no | en_proceso | esperar |
EPR | El SII procesó el envío y no reportó rechazos ni reparos: el documento quedó aceptado. | sí | aceptado | ninguna |
RPR | Aceptado con reparos: el SII dejó observaciones. El documento es válido y exigible; no hay que reemitirlo. | sí | aceptado | ninguna |
accepted | Documento importado del Respaldo del SII: el Servicio ya lo había aceptado cuando se emitió en tu sistema anterior. No hay envío que consultar. | sí | archivistico | ninguna |
RFR | Rechazo por firma: el SII no pudo validar la firma electrónica. No es un problema de tus datos. El folio queda quemado. | sí | rechazado | contactar_soporte |
RCT | Rechazo por carátula: los datos de la resolución que te autoriza a facturar no calzan con los del SII. Reemitir antes de corregirlo repite el rechazo y gasta otro folio. | sí | rechazado | contactar_soporte |
RSC | Rechazo por schema: el XML no pasó la validación XSD del SII. Es un problema de cómo se genera el documento. El folio queda quemado. | sí | rechazado | contactar_soporte |
RCH | El SII aceptó el envío y rechazó este documento por su contenido. Corrige el dato observado y emite uno nuevo con folio nuevo. | sí | rechazado | reemitir |
stuck | El SII no dio veredicto dentro de la ventana del seguimiento y el proceso se agotó. No es un rechazo: el documento puede estar aceptado y no lo sabemos. | no | requiere_accion | reintentar_consulta |
sin_permiso_sii | El SII respondió 106 al consultar: el RUT de tu certificado no está enrolado como usuario autorizado de la empresa. Es un fallo de la consulta, no un veredicto. Enrola al usuario en Mi SII → Usuarios autorizados. | no | requiere_accion | accion_en_sii |
stuck y sin_permiso_sii son terminal: false a propósito: en los dos casos el
SII no juzgó el documento. Por eso refresh-status sí los vuelve a consultar, y
por eso no emitas un duplicado mientras estén así: quemarías otro folio por
un documento que probablemente ya está aceptado.
Dos estados históricos que el filtro sigue aceptando
awaiting_sii y aceptado_con_reparos se publicaron alguna vez y hoy ningún
proceso de Notta los escribe: producción no tiene ni un documento con ellos. Por
eso salieron de la tabla. Si escribiste una query con ellos leyendo nuestra
documentación anterior, ?sii_status=awaiting_sii y
?sii_status=aceptado_con_reparos siguen siendo valores válidos en
GET /dtes y no devuelven 422: no vas a recibir filas, pero tu integración no
se rompe. En código nuevo usa RPR en lugar de aceptado_con_reparos.
Cómo esperar un DTE
Hay dos caminos, y las reglas de decisión son las mismas en los dos.
- Push (
webhook): registras una URL conPOST /api/v1/webhooksy Notta te hace POST con cada transición, firmada y con reintentos. No esperas nada: tu handler recibe eldatacon los mismosterminal,categoriayaccionde abajo. Es el camino si puedes exponer una URL https pública. Ver Webhooks. - Pull: consultas tú. Es lo que sigue esta sección, y es además el camino de
recuperación cuando una entrega de webhook no llega (
GET /dtes?polled_since=).
Tres reglas, en orden:
- Corta por
estado.terminal, nunca porsii_status === "EPR". Un rechazo también es final: un bucle que esperaEPRsobre unRCHgira para siempre. - Ramifica por
estado.categoria, no por el código. Son cinco casillas y cubren todo el universo, incluidos los códigos que todavía no conocemos. - Un código que no reconoces no es terminal: sigue esperando. Nunca lo trates como éxito.
El cliente de TypeScript de Notta trae este mismo bucle listo, con backoff y con
el corte por estado.terminal. Todavía no está publicado en npm, así que hoy
el camino es el fetch de arriba; cuando se publique, la llamada equivalente es:
No leas `sii_status` como si fuera un enum cerrado
El SII no publica una lista cerrada de códigos, y Notta guarda verbatim lo que
responde. Un switch (sii_status) con un default que asume éxito es un bug
esperando su código nuevo; un switch (estado.categoria) no, porque las
categorías sí son nuestras y sí son cerradas.
Cuánto tarda: la cadencia del seguimiento
No hace falta que fuerces nada. Cada DTE emitido publica un seguimiento durable que lo lleva a su estado final por su cuenta, con esta cadencia de consultas al SII:
| Tramo | Consultas al SII |
|---|---|
| Primeros 5 minutos | 11: la inmediata, más una cada 30 segundos |
| Del minuto 5 al 10 | 5: una por minuto |
| Del minuto 15 a las 15 h 45 min | 6: a los 5 min, 30 min, 1 h, 2 h, 4 h y 8 h de la anterior |
| Desde las 15 h 45 min | 7: una cada 24 horas |
Son 29 consultas repartidas en una ventana de 7 d 15 h 45 min. Ese es el
número exacto, no "7 días": si se agota sin veredicto, el documento queda en
stuck y ahí sí necesita que alguien intervenga.
En la práctica el grueso se resuelve en los primeros minutos. La estadística de
producción explica por qué -11 es tan común: 221 de los 283 documentos que
llegaron a un estado terminal pasaron por él, con una permanencia promedio de
213 segundos y un máximo de 3 h 46 min. Ver un -11 no significa que algo
salió mal; significa que el SII todavía no registró el envío.
Para enterarte de las transiciones sin preguntar, registra un webhook: cada una
de esas consultas que cambia el estado dispara una entrega a tu URL. Si prefieres
preguntar tú, GET /dtes/{id}/events es el endpoint canónico de pull: devuelve
la historia completa en orden cronológico, con la glosa del SII, incluidos los
estados transitorios que GET /dtes/{id} ya no muestra. Para muchos documentos a
la vez, GET /dtes acepta sii_status y polled_since, ver
Referencia API de DTEs.
refresh-status es una escotilla, no el seguimiento
POST /dtes/{id}/refresh-status existe para revivir un seguimiento que se murió.
Tiene tres respuestas 2xx y dos de las tres no hacen nada:
| Respuesta | HTTP | Qué significa |
|---|---|---|
refresh_enqueued | 202 | La única que actúa: se encoló una consulta nueva al SII. |
already_terminal | 200 | El SII ya juzgó el documento. Puede ser un rechazo: trae sii_glosa y estado. Léelos antes de darlo por bueno. |
poll_in_progress | 200 | El seguimiento sigue vivo. Trae retry_after en segundos: cuánto falta para que esta llamada deje de ser un no-op. |
El gate que decide entre poll_in_progress y refresh_enqueued es el reloj: si
sii_last_polled se movió hace menos de 25 h, se asume que el seguimiento
está vivo y la llamada no encola nada. El umbral no es arbitrario: supera la
espera legítima más larga de la cadencia (24 h) con una hora de margen. stuck y
sin_permiso_sii se saltan ese gate: ahí ya no hay nadie consultando, y la
escotilla es justo para eso.
Llamarlo en bucle no acelera nada y abre una sesión más contra el SII con tu certificado por cada llamada.
El universo del SII es abierto
El instructivo del SII cierra su tabla de códigos de estado con una fila
literal: «Otros (no enumerados)». El seguimiento de Notta guarda verbatim lo
que responde el Servicio, así que en producción ya hay códigos fuera de la tabla
de arriba: 106 y 107 viven hoy en el historial de estados de documentos
reales.
Por eso el contrato está partido en dos mitades con reglas distintas:
estado.codees un string, no un enum. Declararlo cerrado obligaría a rechazar valores que la propia base de datos contiene.estado.categoriayestado.accionsí son cerrados, porque son vocabulario de Notta. Un código que no conocemos igual cae en una casilla accionable:terminal: false,categoria: "en_proceso"yaccion: "contactar_soporte". Nuncaaccion: "ninguna", que se leería como éxito.
Si te topas con un code que no está en esta página, trátalo como no terminal y
escríbenos con el track_id del documento.
Próximos pasos
- Referencia API de DTEs:
GET /dtes/{id}/events, los filtros del listado y el contrato completo derefresh-status. - Webhooks: el mismo bloque
estado, pero por push, con firma y reintentos. - Notta para agentes: el contrato de errores y el de estados, juntos, con el prompt de arranque.
- Emitir Factura 33: la guía del caso más común, de punta a punta.
- Errores: el catálogo de
codeynext_actionpara el otro lado del contrato.
Última actualización