Ejemplos
Flujos completos que puedes copiar y adaptar. Cada uno va desde el input crudo hasta un documento aceptado por el SII, incluyendo almacenamiento, reintentos y manejo de errores.
Estos ejemplos usan la API planificada para la 1.0. La versión publicada
0.0.2 es un placeholder, y los detalles pueden cambiar antes de la 1.0.
Un tipo 33 con una línea afecta y una exenta: construir, timbrar, firmar, enviar y consultar el estado desde un job.
Emitir una nota de créditoUn tipo 61 que referencia la factura 1024 para anularla (código 1) o corregir sus montos (código 3).
Empieza por la factura: la nota de crédito reutiliza sus módulos y corrige la factura que ahí se emite.
Tres reglas que siguen ambos ejemplos#
Nunca reutilices un folio#
Cada documento de un tipo recibe su propio folio del rango del CAF. Asígnalo en la misma transacción que guarda el documento, para que un error de validación no consuma uno:
const signed = await db.transaction(async (tx) => {
const folio = await tx.folios.next(33)
const signed = await buildInvoice({ folio, receiver, items })
await tx.invoices.insert({ folio, xml: signed.xml, state: 'signed' })
return signed
})Guarda antes de enviar#
El XML firmado es el documento legal. Guárdalo primero, luego envía, y después guarda el track ID:
const { trackId } = await sendToSii(signed, { certificate, ...SII })
await db.invoices.update(signed.folio, { trackId, state: 'sent' })Decide según el código#
Toda falla es un DteError con un code estable. Los mensajes son genéricos y nunca incluyen RUTs ni montos, así que no los parsees:
import { DteError } from 'dte-sdk'
if (error instanceof DteError && error.code === 'SII_UNAVAILABLE') {
// keep the document as 'signed' and retry the upload later
}Ejecuta ambos ejemplos con SII_ENVIRONMENT=certification hasta que el SII
te autorice para producción. El código es el mismo en ambos ambientes.