stampDte()
Agrega el timbre electrónico (TED, Timbre Electrónico DTE) a un documento, usando el CAF que el SII autorizó para su rango de folios.
Uso básico#
import { readFile } from 'node:fs/promises'
import { parseCaf, stampDte } from 'dte-sdk'
const caf = parseCaf(await readFile(process.env.DTE_CAF_33_PATH!, 'latin1'))
const stamped = stampDte(dte, caf)
stamped.ted // '<TED version="1.0"><DD><RE>76123456-0</RE><TD>33</TD><F>1024</F>…</TED>'
stamped.pdf417 // payload for the PDF417 barcode on the printed versionFirma de tipo#
function stampDte(dte: Dte, caf: Caf | string, options?: { stampedAt?: Date }): StampedDte
function parseCaf(xml: string): Caf
interface Caf {
type: DteType
issuerRut: string
range: { from: number; to: number }
authorizedAt: string
expiresAt: string
}
// StampedDte = Dte + { ted: string; pdf417: string }Parámetros#
dte(Dte) - Un documento creado concreateDte().caf(Caf | string) - El CAF del tipo del documento, ya sea leído conparseCaf()o como el string XML original del CAF. Si timbras muchos documentos, léelo una vez y reutiliza elCaf.options(opcional)stampedAt(Date, por defecto: ahora) - La marca de tiempo que se escribe en el TED. Fíjala en tus tests para obtener una salida reproducible.
Valor de retorno#
Retorna un StampedDte: el mismo documento más dos campos.
ted(string) - El elemento XML<TED>, firmado con la llave privada del CAF.pdf417(string) - El contenido a dibujar como código de barras PDF417 en la versión impresa del documento. dte-sdk no genera PDFs ni códigos de barras; entrega este string a tu propio proceso de impresión.
El dte de entrada no se modifica.
Errores#
| Código | Cuándo |
|---|---|
FOLIO_OUT_OF_RANGE | El folio del documento está fuera de caf.range |
CAF_MISMATCH | El CAF es de otro tipo de documento o de otro RUT emisor |
CAF_EXPIRED | La fecha del timbre (stampedAt, o ahora) es posterior a caf.expiresAt |
En la práctica, los tres significan lo mismo: este CAF no puede timbrar este documento. Solicita o carga el CAF correcto; reintentar no sirve.
parseCaf()#
El SII te entrega un CAF (Código de Autorización de Folios) como archivo XML por cada rango de folios que solicitas. parseCaf() lo lee y lo convierte en un Caf tipado:
import { readFile } from 'node:fs/promises'
import { parseCaf } from 'dte-sdk'
const caf = parseCaf(await readFile(process.env.DTE_CAF_33_PATH!, 'latin1'))
caf.type // 33
caf.issuerRut // '76123456-0'
caf.range // { from: 1001, to: 2000 }
caf.authorizedAt // '2026-10-15'
caf.expiresAt // '2027-04-15'Los archivos CAF vienen codificados en ISO-8859-1, así que en Node léelos como latin1 para no romper los caracteres con tilde.
Trata el CAF como un secreto. El XML del CAF contiene la llave privada
con la que se genera el timbre. Mantenlo fuera de tu repositorio y cárgalo
desde un gestor de secretos o una ruta protegida. Los mensajes de DteError
nunca incluyen llaves privadas del CAF.
parseCaf() solo lee el archivo. El rango de folios y el vencimiento se verifican cuando llamas a stampDte().
Ejemplos#
Revisar el rango antes de asignar un folio#
import type { Caf } from 'dte-sdk'
function hasFolio(caf: Caf, folio: number): boolean {
return folio >= caf.range.from && folio <= caf.range.to
}
function foliosLeft(caf: Caf, lastUsed: number): number {
return caf.range.to - lastUsed
}
hasFolio(caf, 1024) // true
foliosLeft(caf, 1024) // 976Avisa a tu equipo bastante antes de que foliosLeft() llegue a cero: hay que solicitar un CAF nuevo antes de poder emitir más documentos de ese tipo.
Un CAF por tipo de documento#
Cada CAF cubre un solo tipo de documento. Mantén uno por cada tipo que emites y elígelo según dte.type:
import { parseCaf, stampDte, type Caf, type DteType } from 'dte-sdk'
const cafs = new Map<DteType, Caf>([
[33, parseCaf(invoiceCafXml)],
[61, parseCaf(creditNoteCafXml)],
])
const stamped = stampDte(dte, cafs.get(dte.type)!)Timbrar una nota de crédito con el CAF de facturas lanza CAF_MISMATCH.
Timbres reproducibles en tests#
import { stampDte, toXml } from 'dte-sdk'
const stamped = stampDte(dte, caf, {
stampedAt: new Date('2026-10-28T10:15:00-03:00'),
})
expect(toXml(stamped)).toMatchSnapshot()Manejar errores de timbraje#
import { DteError, stampDte } from 'dte-sdk'
try {
return stampDte(dte, caf)
} catch (error) {
if (!(error instanceof DteError)) throw error
switch (error.code) {
case 'FOLIO_OUT_OF_RANGE':
throw new Error('Folio range exhausted: load a new CAF')
case 'CAF_EXPIRED':
throw new Error('CAF expired: request a new one')
case 'CAF_MISMATCH':
throw new Error('Wrong CAF for this document type or issuer')
default:
throw error
}
}Funciones relacionadas#
createDte()- Construye el documento que timbrassignDte()- Siguiente paso: firmar el documento timbradotoXml()- Mira dónde queda el<TED>dentro del XML