Saltar al contenido
dte-sdk

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#

TypeScript
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 version

Firma de tipo#

TypeScript
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 con createDte().
  • caf (Caf | string) - El CAF del tipo del documento, ya sea leído con parseCaf() o como el string XML original del CAF. Si timbras muchos documentos, léelo una vez y reutiliza el Caf.
  • 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ódigoCuándo
FOLIO_OUT_OF_RANGEEl folio del documento está fuera de caf.range
CAF_MISMATCHEl CAF es de otro tipo de documento o de otro RUT emisor
CAF_EXPIREDLa 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:

TypeScript
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#

TypeScript
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)  // 976

Avisa 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:

TypeScript
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#

TypeScript
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#

TypeScript
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 timbras
  • signDte() - Siguiente paso: firmar el documento timbrado
  • toXml() - Mira dónde queda el <TED> dentro del XML