Skip to content

stampDte()

Adds the electronic stamp (TED, Timbre Electrónico DTE) to a document, using the CAF the SII authorized for its folio range.

Basic Usage#

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

Type Signature#

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 }

Parameters#

  • dte (Dte) - A document from createDte().
  • caf (Caf | string) - The CAF for the document's type, either parsed with parseCaf() or as the raw CAF XML string. When you stamp many documents, parse once and reuse the Caf.
  • options (optional)
    • stampedAt (Date, default: now) - The timestamp written into the TED. Pin it in tests for reproducible output.

Return Value#

Returns a StampedDte: the same document plus two fields.

  • ted (string) - The <TED> XML element, signed with the CAF private key.
  • pdf417 (string) - The payload to render as a PDF417 barcode on the printed version of the document. dte-sdk does not render PDFs or barcodes; hand this string to your own printing pipeline.

The input dte is not modified.

Errors#

CodeWhen
FOLIO_OUT_OF_RANGEThe document's folio is outside caf.range
CAF_MISMATCHThe CAF is for a different document type, or for a different issuer RUT
CAF_EXPIREDThe stamp date (stampedAt, or now) is after caf.expiresAt

All three mean the same thing operationally: this CAF can't stamp this document. Request or load the right CAF; retrying won't help.

parseCaf()#

The SII hands you a CAF (Código de Autorización de Folios) as an XML file for each folio range you request. parseCaf() reads it into a typed Caf:

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'

CAF files are encoded as ISO-8859-1, so read them as latin1 in Node to keep accented characters intact.

Treat the CAF as a secret. The CAF XML contains the private key that produces the stamp. Keep it out of your repository and load it from a secret store or a protected path. DteError messages never include CAF private keys.

parseCaf() only reads the file. Folio range and expiry are checked when you call stampDte().

Examples#

Check the Range Before Allocating a 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

Warn your team well before foliosLeft() reaches zero: a new CAF has to be requested before you can issue more documents of that type.

One CAF per Document Type#

Each CAF covers a single document type. Keep one per type you issue and pick it by 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)!)

Stamping a credit note with the invoice CAF throws CAF_MISMATCH.

Reproducible Stamps in 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()

Handling Stamp Errors#

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
  }
}
  • createDte() - Builds the document you stamp
  • signDte() - Next step: sign the stamped document
  • toXml() - See where the <TED> lands in the XML